Browse Source
fix(sharing): add command to fix broken shares after ownership transferring
fix(sharing): add command to fix broken shares after ownership transferring
Signed-off-by: Luka Trovic <luka@nextcloud.com>pull/49612/head
6 changed files with 211 additions and 1 deletions
-
1apps/files_sharing/appinfo/info.xml
-
1apps/files_sharing/composer/composer/autoload_classmap.php
-
1apps/files_sharing/composer/composer/autoload_static.php
-
65apps/files_sharing/lib/Command/FixShareOwners.php
-
28apps/files_sharing/lib/OrphanHelper.php
-
116apps/files_sharing/tests/Command/FixShareOwnersTest.php
@ -0,0 +1,65 @@ |
|||||
|
<?php |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
/** |
||||
|
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors |
||||
|
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
|
*/ |
||||
|
|
||||
|
namespace OCA\Files_Sharing\Command; |
||||
|
|
||||
|
use OC\Core\Command\Base; |
||||
|
use OCA\Files_Sharing\OrphanHelper; |
||||
|
use Symfony\Component\Console\Input\InputInterface; |
||||
|
use Symfony\Component\Console\Input\InputOption; |
||||
|
use Symfony\Component\Console\Output\OutputInterface; |
||||
|
|
||||
|
class FixShareOwners extends Base { |
||||
|
public function __construct( |
||||
|
private readonly OrphanHelper $orphanHelper, |
||||
|
) { |
||||
|
parent::__construct(); |
||||
|
} |
||||
|
|
||||
|
protected function configure(): void { |
||||
|
$this |
||||
|
->setName('sharing:fix-share-owners') |
||||
|
->setDescription('Fix owner of broken shares after transfer ownership on old versions') |
||||
|
->addOption( |
||||
|
'dry-run', |
||||
|
null, |
||||
|
InputOption::VALUE_NONE, |
||||
|
'only show which shares would be updated' |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public function execute(InputInterface $input, OutputInterface $output): int { |
||||
|
$shares = $this->orphanHelper->getAllShares(); |
||||
|
$dryRun = $input->getOption('dry-run'); |
||||
|
$count = 0; |
||||
|
|
||||
|
foreach ($shares as $share) { |
||||
|
if ($this->orphanHelper->isShareValid($share['owner'], $share['fileid']) || !$this->orphanHelper->fileExists($share['fileid'])) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
$owner = $this->orphanHelper->findOwner($share['fileid']); |
||||
|
|
||||
|
if ($owner !== null) { |
||||
|
if ($dryRun) { |
||||
|
$output->writeln("Share with id <info>{$share['id']}</info> (target: <info>{$share['target']}</info>) can be updated to owner <info>$owner</info>"); |
||||
|
} else { |
||||
|
$this->orphanHelper->updateShareOwner($share['id'], $owner); |
||||
|
$output->writeln("Share with id <info>{$share['id']}</info> (target: <info>{$share['target']}</info>) updated to owner <info>$owner</info>"); |
||||
|
} |
||||
|
$count++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if ($count === 0) { |
||||
|
$output->writeln('No broken shares detected'); |
||||
|
} |
||||
|
|
||||
|
return static::SUCCESS; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,116 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors |
||||
|
* SPDX-License-Identifier: AGPL-3.0-only |
||||
|
*/ |
||||
|
namespace OCA\Files_Sharing\Tests\Command; |
||||
|
|
||||
|
use OCA\Files_Sharing\Command\FixShareOwners; |
||||
|
use OCA\Files_Sharing\OrphanHelper; |
||||
|
use Symfony\Component\Console\Input\InputInterface; |
||||
|
use Symfony\Component\Console\Output\OutputInterface; |
||||
|
use Test\TestCase; |
||||
|
|
||||
|
/** |
||||
|
* Class FixShareOwnersTest |
||||
|
* |
||||
|
* @package OCA\Files_Sharing\Tests\Command |
||||
|
*/ |
||||
|
class FixShareOwnersTest extends TestCase { |
||||
|
/** |
||||
|
* @var FixShareOwners |
||||
|
*/ |
||||
|
private $command; |
||||
|
|
||||
|
/** |
||||
|
* @var OrphanHelper|\PHPUnit\Framework\MockObject\MockObject |
||||
|
*/ |
||||
|
private $orphanHelper; |
||||
|
|
||||
|
protected function setUp(): void { |
||||
|
parent::setUp(); |
||||
|
|
||||
|
$this->orphanHelper = $this->createMock(OrphanHelper::class); |
||||
|
$this->command = new FixShareOwners($this->orphanHelper); |
||||
|
} |
||||
|
|
||||
|
public function testExecuteNoSharesDetected() { |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('getAllShares') |
||||
|
->willReturn([ |
||||
|
['id' => 1, 'owner' => 'user1', 'fileid' => 1, 'target' => 'target1'], |
||||
|
['id' => 2, 'owner' => 'user2', 'fileid' => 2, 'target' => 'target2'], |
||||
|
]); |
||||
|
$this->orphanHelper->expects($this->exactly(2)) |
||||
|
->method('isShareValid') |
||||
|
->willReturn(true); |
||||
|
|
||||
|
$input = $this->createMock(InputInterface::class); |
||||
|
$output = $this->createMock(OutputInterface::class); |
||||
|
|
||||
|
$output->expects($this->once()) |
||||
|
->method('writeln') |
||||
|
->with('No broken shares detected'); |
||||
|
$this->command->execute($input, $output); |
||||
|
} |
||||
|
|
||||
|
public function testExecuteSharesDetected() { |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('getAllShares') |
||||
|
->willReturn([ |
||||
|
['id' => 1, 'owner' => 'user1', 'fileid' => 1, 'target' => 'target1'], |
||||
|
['id' => 2, 'owner' => 'user2', 'fileid' => 2, 'target' => 'target2'], |
||||
|
]); |
||||
|
$this->orphanHelper->expects($this->exactly(2)) |
||||
|
->method('isShareValid') |
||||
|
->willReturnOnConsecutiveCalls(true, false); |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('fileExists') |
||||
|
->willReturn(true); |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('findOwner') |
||||
|
->willReturn('newOwner'); |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('updateShareOwner'); |
||||
|
|
||||
|
$input = $this->createMock(InputInterface::class); |
||||
|
$output = $this->createMock(OutputInterface::class); |
||||
|
|
||||
|
$output->expects($this->once()) |
||||
|
->method('writeln') |
||||
|
->with('Share with id <info>2</info> (target: <info>target2</info>) updated to owner <info>newOwner</info>'); |
||||
|
$this->command->execute($input, $output); |
||||
|
} |
||||
|
|
||||
|
public function testExecuteSharesDetectedDryRun() { |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('getAllShares') |
||||
|
->willReturn([ |
||||
|
['id' => 1, 'owner' => 'user1', 'fileid' => 1, 'target' => 'target1'], |
||||
|
['id' => 2, 'owner' => 'user2', 'fileid' => 2, 'target' => 'target2'], |
||||
|
]); |
||||
|
$this->orphanHelper->expects($this->exactly(2)) |
||||
|
->method('isShareValid') |
||||
|
->willReturnOnConsecutiveCalls(true, false); |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('fileExists') |
||||
|
->willReturn(true); |
||||
|
$this->orphanHelper->expects($this->once()) |
||||
|
->method('findOwner') |
||||
|
->willReturn('newOwner'); |
||||
|
$this->orphanHelper->expects($this->never()) |
||||
|
->method('updateShareOwner'); |
||||
|
|
||||
|
$input = $this->createMock(InputInterface::class); |
||||
|
$output = $this->createMock(OutputInterface::class); |
||||
|
|
||||
|
$output->expects($this->once()) |
||||
|
->method('writeln') |
||||
|
->with('Share with id <info>2</info> (target: <info>target2</info>) can be updated to owner <info>newOwner</info>'); |
||||
|
$input->expects($this->once()) |
||||
|
->method('getOption') |
||||
|
->with('dry-run') |
||||
|
->willReturn(true); |
||||
|
$this->command->execute($input, $output); |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue