CleanUp.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\Files_Trashbin\Command;
  8. use OCP\Files\IRootFolder;
  9. use OCP\IDBConnection;
  10. use OCP\IUserBackend;
  11. use OCP\IUserManager;
  12. use Symfony\Component\Console\Command\Command;
  13. use Symfony\Component\Console\Exception\InvalidOptionException;
  14. use Symfony\Component\Console\Input\InputArgument;
  15. use Symfony\Component\Console\Input\InputInterface;
  16. use Symfony\Component\Console\Input\InputOption;
  17. use Symfony\Component\Console\Output\OutputInterface;
  18. class CleanUp extends Command {
  19. /** @var IUserManager */
  20. protected $userManager;
  21. /** @var IRootFolder */
  22. protected $rootFolder;
  23. /** @var \OCP\IDBConnection */
  24. protected $dbConnection;
  25. /**
  26. * @param IRootFolder $rootFolder
  27. * @param IUserManager $userManager
  28. * @param IDBConnection $dbConnection
  29. */
  30. public function __construct(IRootFolder $rootFolder, IUserManager $userManager, IDBConnection $dbConnection) {
  31. parent::__construct();
  32. $this->userManager = $userManager;
  33. $this->rootFolder = $rootFolder;
  34. $this->dbConnection = $dbConnection;
  35. }
  36. protected function configure() {
  37. $this
  38. ->setName('trashbin:cleanup')
  39. ->setDescription('Remove deleted files')
  40. ->addArgument(
  41. 'user_id',
  42. InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
  43. 'remove deleted files of the given user(s)'
  44. )
  45. ->addOption(
  46. 'all-users',
  47. null,
  48. InputOption::VALUE_NONE,
  49. 'run action on all users'
  50. );
  51. }
  52. protected function execute(InputInterface $input, OutputInterface $output): int {
  53. $users = $input->getArgument('user_id');
  54. $verbose = $input->getOption('verbose');
  55. if ((!empty($users)) and ($input->getOption('all-users'))) {
  56. throw new InvalidOptionException('Either specify a user_id or --all-users');
  57. } elseif (!empty($users)) {
  58. foreach ($users as $user) {
  59. if ($this->userManager->userExists($user)) {
  60. $output->writeln("Remove deleted files of <info>$user</info>");
  61. $this->removeDeletedFiles($user, $output, $verbose);
  62. } else {
  63. $output->writeln("<error>Unknown user $user</error>");
  64. return 1;
  65. }
  66. }
  67. } elseif ($input->getOption('all-users')) {
  68. $output->writeln('Remove deleted files for all users');
  69. foreach ($this->userManager->getBackends() as $backend) {
  70. $name = get_class($backend);
  71. if ($backend instanceof IUserBackend) {
  72. $name = $backend->getBackendName();
  73. }
  74. $output->writeln("Remove deleted files for users on backend <info>$name</info>");
  75. $limit = 500;
  76. $offset = 0;
  77. do {
  78. $users = $backend->getUsers('', $limit, $offset);
  79. foreach ($users as $user) {
  80. $output->writeln(" <info>$user</info>");
  81. $this->removeDeletedFiles($user, $output, $verbose);
  82. }
  83. $offset += $limit;
  84. } while (count($users) >= $limit);
  85. }
  86. } else {
  87. throw new InvalidOptionException('Either specify a user_id or --all-users');
  88. }
  89. return 0;
  90. }
  91. /**
  92. * remove deleted files for the given user
  93. */
  94. protected function removeDeletedFiles(string $uid, OutputInterface $output, bool $verbose): void {
  95. \OC_Util::tearDownFS();
  96. \OC_Util::setupFS($uid);
  97. $path = '/' . $uid . '/files_trashbin';
  98. if ($this->rootFolder->nodeExists($path)) {
  99. $node = $this->rootFolder->get($path);
  100. if ($verbose) {
  101. $output->writeln("Deleting <info>" . \OC_Helper::humanFileSize($node->getSize()) . "</info> in trash for <info>$uid</info>.");
  102. }
  103. $node->delete();
  104. if ($this->rootFolder->nodeExists($path)) {
  105. $output->writeln("<error>Trash folder sill exists after attempting to delete it</error>");
  106. return;
  107. }
  108. $query = $this->dbConnection->getQueryBuilder();
  109. $query->delete('files_trash')
  110. ->where($query->expr()->eq('user', $query->createParameter('uid')))
  111. ->setParameter('uid', $uid);
  112. $query->execute();
  113. } else {
  114. if ($verbose) {
  115. $output->writeln("No trash found for <info>$uid</info>");
  116. }
  117. }
  118. }
  119. }