Browse Source
Introduce console command to transfer ownerships of files - refs #19154
remotes/origin/users-ajaxloadgroups
Introduce console command to transfer ownerships of files - refs #19154
remotes/origin/users-ajaxloadgroups
2 changed files with 240 additions and 2 deletions
@ -0,0 +1,231 @@ |
|||
<?php |
|||
/** |
|||
* @author Thomas Müller <thomas.mueller@tmit.eu> |
|||
* |
|||
* @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 <http://www.gnu.org/licenses/> |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Files\Command; |
|||
|
|||
use OC\Files\Filesystem; |
|||
use OC\Files\View; |
|||
use OCP\Files\FileInfo; |
|||
use OCP\Files\Folder; |
|||
use OCP\Files\IRootFolder; |
|||
use OCP\IUserManager; |
|||
use OCP\Share\IManager; |
|||
use OCP\Share\IShare; |
|||
use Symfony\Component\Console\Command\Command; |
|||
use Symfony\Component\Console\Helper\ProgressBar; |
|||
use Symfony\Component\Console\Input\InputArgument; |
|||
use Symfony\Component\Console\Input\InputInterface; |
|||
use Symfony\Component\Console\Output\OutputInterface; |
|||
|
|||
class TransferOwnership extends Command { |
|||
|
|||
/** @var IUserManager $userManager */ |
|||
private $userManager; |
|||
|
|||
/** @var IManager */ |
|||
private $shareManager; |
|||
|
|||
/** @var FileInfo[] */ |
|||
private $allFiles = []; |
|||
|
|||
/** @var FileInfo[] */ |
|||
private $encryptedFiles = []; |
|||
|
|||
/** @var IShare[] */ |
|||
private $shares = []; |
|||
|
|||
/** @var string */ |
|||
private $sourceUser; |
|||
|
|||
/** @var string */ |
|||
private $destinationUser; |
|||
|
|||
/** @var string */ |
|||
private $finalTarget; |
|||
|
|||
/** @var IRootFolder */ |
|||
private $rootFolder; |
|||
|
|||
public function __construct(IUserManager $userManager, IManager $shareManager, IRootFolder $rootFolder) { |
|||
$this->userManager = $userManager; |
|||
$this->shareManager = $shareManager; |
|||
$this->rootFolder = $rootFolder; |
|||
parent::__construct(); |
|||
} |
|||
|
|||
protected function configure() { |
|||
$this |
|||
->setName('files:transfer-ownership') |
|||
->setDescription('move file and folder from one user to another') |
|||
->addArgument( |
|||
'source-user', |
|||
InputArgument::REQUIRED, |
|||
'owner of files which shall be moved' |
|||
) |
|||
->addArgument( |
|||
'destination-user', |
|||
InputArgument::REQUIRED, |
|||
'user who will be the new owner of the files' |
|||
); |
|||
} |
|||
|
|||
protected function execute(InputInterface $input, OutputInterface $output) { |
|||
$this->sourceUser = $input->getArgument('source-user'); |
|||
$this->destinationUser = $input->getArgument('destination-user'); |
|||
if (!$this->userManager->userExists($this->sourceUser)) { |
|||
$output->writeln("<error>Unknown source user $this->sourceUser</error>"); |
|||
return; |
|||
} |
|||
if (!$this->userManager->userExists($this->destinationUser)) { |
|||
$output->writeln("<error>Unknown destination user $this->destinationUser</error>"); |
|||
return; |
|||
} |
|||
|
|||
$date = date('c'); |
|||
$this->finalTarget = "$this->destinationUser/files/transferred from $this->sourceUser on $date"; |
|||
|
|||
// setup filesystem
|
|||
Filesystem::initMountPoints($this->sourceUser); |
|||
Filesystem::initMountPoints($this->destinationUser); |
|||
|
|||
// analyse source folder
|
|||
$this->analyse($output); |
|||
|
|||
// collect all the shares
|
|||
$this->collectUsersShares($output); |
|||
|
|||
// transfer the files
|
|||
$this->transfer($output); |
|||
|
|||
// restore the shares
|
|||
$this->restoreShares($output); |
|||
} |
|||
|
|||
private function walkFiles(View $view, $path, \Closure $callBack) { |
|||
foreach ($view->getDirectoryContent($path) as $fileInfo) { |
|||
if (!$callBack($fileInfo)) { |
|||
return; |
|||
} |
|||
if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) { |
|||
$this->walkFiles($view, $fileInfo->getPath(), $callBack); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param OutputInterface $output |
|||
* @throws \Exception |
|||
*/ |
|||
protected function analyse(OutputInterface $output) { |
|||
$view = new View(); |
|||
$output->writeln("Analysing files of $this->sourceUser ..."); |
|||
$progress = new ProgressBar($output); |
|||
$progress->start(); |
|||
$self = $this; |
|||
$this->walkFiles($view, "$this->sourceUser/files", |
|||
function (FileInfo $fileInfo) use ($progress, $self) { |
|||
if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) { |
|||
return true; |
|||
} |
|||
$progress->advance(); |
|||
$this->allFiles[] = $fileInfo; |
|||
if ($fileInfo->isEncrypted()) { |
|||
$this->encryptedFiles[] = $fileInfo; |
|||
} |
|||
return true; |
|||
}); |
|||
$progress->finish(); |
|||
$output->writeln(''); |
|||
|
|||
// no file is allowed to be encrypted
|
|||
if (!empty($this->encryptedFiles)) { |
|||
$output->writeln("<error>Some files are encrypted - please decrypt them first</error>"); |
|||
foreach($this->encryptedFiles as $encryptedFile) { |
|||
/** @var FileInfo $encryptedFile */ |
|||
$output->writeln(" " . $encryptedFile->getPath()); |
|||
} |
|||
throw new \Exception('Execution terminated.'); |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* @param OutputInterface $output |
|||
*/ |
|||
private function collectUsersShares(OutputInterface $output) { |
|||
$output->writeln("Collecting all share information for files and folder of $this->sourceUser ..."); |
|||
|
|||
$progress = new ProgressBar($output, count($this->shares)); |
|||
foreach([\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE] as $shareType) { |
|||
$offset = 0; |
|||
while (true) { |
|||
$sharePage = $this->shareManager->getSharesBy($this->sourceUser, $shareType, null, true, 50, $offset); |
|||
$progress->advance(count($sharePage)); |
|||
if (empty($sharePage)) { |
|||
break; |
|||
} |
|||
$this->shares = array_merge($this->shares, $sharePage); |
|||
$offset += 50; |
|||
} |
|||
} |
|||
|
|||
$progress->finish(); |
|||
$output->writeln(''); |
|||
} |
|||
|
|||
/** |
|||
* @param OutputInterface $output |
|||
*/ |
|||
protected function transfer(OutputInterface $output) { |
|||
$view = new View(); |
|||
$output->writeln("Transferring files to $this->finalTarget ..."); |
|||
$view->rename("$this->sourceUser/files", $this->finalTarget); |
|||
// because the files folder is moved away we need to recreate it
|
|||
$view->mkdir("$this->sourceUser/files"); |
|||
} |
|||
|
|||
/** |
|||
* @param OutputInterface $output |
|||
*/ |
|||
private function restoreShares(OutputInterface $output) { |
|||
$output->writeln("Restoring shares ..."); |
|||
$progress = new ProgressBar($output, count($this->shares)); |
|||
/** @var Folder $sourceRoot */ |
|||
|
|||
foreach($this->shares as $share) { |
|||
if ($share->getSharedWith() === $this->destinationUser) { |
|||
$this->shareManager->deleteShare($share); |
|||
} else { |
|||
if ($share->getShareOwner() === $this->sourceUser) { |
|||
$share->setShareOwner($this->destinationUser); |
|||
} |
|||
if ($share->getSharedBy() === $this->sourceUser) { |
|||
$share->setSharedBy($this->destinationUser); |
|||
} |
|||
|
|||
$this->shareManager->updateShare($share); |
|||
} |
|||
$progress->advance(); |
|||
} |
|||
$progress->finish(); |
|||
$output->writeln(''); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue