diff --git a/apps/sharing/lib/Command/AddShareRecipient.php b/apps/sharing/lib/Command/AddShareRecipient.php index 7fe76f5ae3dd2..5742b0816087b 100644 --- a/apps/sharing/lib/Command/AddShareRecipient.php +++ b/apps/sharing/lib/Command/AddShareRecipient.php @@ -27,6 +27,7 @@ public function configure(): void { ->addArgument('class', InputArgument::REQUIRED, 'Recipient class') ->addArgument('value', InputArgument::REQUIRED, 'Recipient value') ->addArgument('instance', InputArgument::OPTIONAL, 'Recipient instance'); + parent::configure(); } #[\Override] @@ -40,7 +41,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var ?non-empty-string $instance */ $instance = $input->getArgument('instance'); - return $this->wrapExecution($output, function () use ($id, $class, $value, $instance): Share { + return $this->wrapExecution($input, $output, function () use ($id, $class, $value, $instance): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->addShareRecipient($this->accessContext, $share, new ShareRecipient($class, $value, $instance)); }); diff --git a/apps/sharing/lib/Command/AddShareSource.php b/apps/sharing/lib/Command/AddShareSource.php index ddd1e0aebc485..2a4b37aa8e741 100644 --- a/apps/sharing/lib/Command/AddShareSource.php +++ b/apps/sharing/lib/Command/AddShareSource.php @@ -25,6 +25,7 @@ public function configure(): void { ->addArgument('id', InputArgument::REQUIRED, 'Share ID') ->addArgument('class', InputArgument::REQUIRED, 'Source class') ->addArgument('value', InputArgument::REQUIRED, 'Source value'); + parent::configure(); } #[\Override] @@ -36,7 +37,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var non-empty-string $value */ $value = $input->getArgument('value'); - return $this->wrapExecution($output, function () use ($id, $class, $value): Share { + return $this->wrapExecution($input, $output, function () use ($id, $class, $value): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->addShareSource($this->accessContext, $share, new ShareSource($class, $value)); }); diff --git a/apps/sharing/lib/Command/CreateShare.php b/apps/sharing/lib/Command/CreateShare.php index 620916b178054..dde7624ff28d3 100644 --- a/apps/sharing/lib/Command/CreateShare.php +++ b/apps/sharing/lib/Command/CreateShare.php @@ -26,6 +26,7 @@ public function configure(): void { ->setName('sharing:create-share') ->setDescription('Create a new share.') ->addArgument('owner', InputArgument::REQUIRED, 'User ID of the owner'); + parent::configure(); } #[\Override] @@ -37,6 +38,6 @@ public function execute(InputInterface $input, OutputInterface $output): int { throw new ShareInvalidException('The owner does not exist: ' . $ownerUid, Server::get(IFactory::class)->get('sharing')->t('The owner does not exist: %s', [$ownerUid])); } - return $this->wrapExecution($output, fn (): Share => $this->manager->createShare(new ShareAccessContext($owner))); + return $this->wrapExecution($input, $output, fn (): Share => $this->manager->createShare(new ShareAccessContext($owner))); } } diff --git a/apps/sharing/lib/Command/DeleteShare.php b/apps/sharing/lib/Command/DeleteShare.php index f5e330624e233..d921b9a4ad296 100644 --- a/apps/sharing/lib/Command/DeleteShare.php +++ b/apps/sharing/lib/Command/DeleteShare.php @@ -24,12 +24,14 @@ public function configure(): void { ->setName('sharing:delete-share') ->setDescription('Delete a share.') ->addArgument('id', InputArgument::REQUIRED, 'Share ID'); + parent::configure(); } #[\Override] public function execute(InputInterface $input, OutputInterface $output): int { /** @var string $id */ $id = $input->getArgument('id'); + $this->applyActor($input); try { try { diff --git a/apps/sharing/lib/Command/GetShare.php b/apps/sharing/lib/Command/GetShare.php index d150d0406924f..1f27891b6a7e8 100644 --- a/apps/sharing/lib/Command/GetShare.php +++ b/apps/sharing/lib/Command/GetShare.php @@ -21,6 +21,7 @@ public function configure(): void { ->setName('sharing:get-share') ->setDescription('Get a share.') ->addArgument('id', InputArgument::REQUIRED, 'Share ID'); + parent::configure(); } #[\Override] @@ -28,6 +29,6 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var string $id */ $id = $input->getArgument('id'); - return $this->wrapExecution($output, fn (): Share => $this->manager->getShare($this->accessContext, $id)); + return $this->wrapExecution($input, $output, fn (): Share => $this->manager->getShare($this->accessContext, $id)); } } diff --git a/apps/sharing/lib/Command/GetShares.php b/apps/sharing/lib/Command/GetShares.php index 09b06da9374c1..215e6f2ca4123 100644 --- a/apps/sharing/lib/Command/GetShares.php +++ b/apps/sharing/lib/Command/GetShares.php @@ -27,10 +27,13 @@ public function configure(): void { ->addOption('filter-source-type-value', '', InputOption::VALUE_REQUIRED, 'Source type value to filter by') ->addOption('last-share-id', '', InputOption::VALUE_REQUIRED, 'Share ID to use as an offset') ->addOption('limit', '', InputOption::VALUE_REQUIRED, 'Maximum number of shares to return'); + parent::configure(); } #[\Override] public function execute(InputInterface $input, OutputInterface $output): int { + $this->applyActor($input); + /** @var ?class-string $filterSourceTypeClass */ $filterSourceTypeClass = $input->getOption('filter-source-type-class'); /** @var ?class-string $filterSourceTypeValue */ diff --git a/apps/sharing/lib/Command/RemoveShareRecipient.php b/apps/sharing/lib/Command/RemoveShareRecipient.php index e52f836e20c90..50873cfb07207 100644 --- a/apps/sharing/lib/Command/RemoveShareRecipient.php +++ b/apps/sharing/lib/Command/RemoveShareRecipient.php @@ -26,6 +26,7 @@ public function configure(): void { ->addArgument('class', InputArgument::REQUIRED, 'Recipient class') ->addArgument('value', InputArgument::REQUIRED, 'Recipient value') ->addArgument('instance', InputArgument::OPTIONAL, 'Recipient instance'); + parent::configure(); } #[\Override] @@ -39,7 +40,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var ?non-empty-string $instance */ $instance = $input->getArgument('instance'); - return $this->wrapExecution($output, function () use ($id, $class, $value, $instance): Share { + return $this->wrapExecution($input, $output, function () use ($id, $class, $value, $instance): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->removeShareRecipient($this->accessContext, $share, new ShareRecipient($class, $value, $instance)); }); diff --git a/apps/sharing/lib/Command/RemoveShareSource.php b/apps/sharing/lib/Command/RemoveShareSource.php index e5a8411c15298..732d73176fc99 100644 --- a/apps/sharing/lib/Command/RemoveShareSource.php +++ b/apps/sharing/lib/Command/RemoveShareSource.php @@ -25,6 +25,7 @@ public function configure(): void { ->addArgument('id', InputArgument::REQUIRED, 'Share ID') ->addArgument('class', InputArgument::REQUIRED, 'Source class') ->addArgument('value', InputArgument::REQUIRED, 'Source value'); + parent::configure(); } #[\Override] @@ -36,7 +37,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var non-empty-string $value */ $value = $input->getArgument('value'); - return $this->wrapExecution($output, function () use ($id, $class, $value): Share { + return $this->wrapExecution($input, $output, function () use ($id, $class, $value): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->removeShareSource($this->accessContext, $share, new ShareSource($class, $value)); }); diff --git a/apps/sharing/lib/Command/SelectSharePermissionPreset.php b/apps/sharing/lib/Command/SelectSharePermissionPreset.php index 42fded2396958..6932961656368 100644 --- a/apps/sharing/lib/Command/SelectSharePermissionPreset.php +++ b/apps/sharing/lib/Command/SelectSharePermissionPreset.php @@ -23,6 +23,7 @@ public function configure(): void { ->setDescription('Select a permission preset for a share.') ->addArgument('id', InputArgument::REQUIRED, 'Share ID') ->addArgument('permission-preset', InputArgument::REQUIRED, 'Permission preset'); + parent::configure(); } #[\Override] @@ -32,7 +33,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var class-string $permissionPresetClass */ $permissionPresetClass = $input->getArgument('permission-preset'); - return $this->wrapExecution($output, function () use ($id, $permissionPresetClass): Share { + return $this->wrapExecution($input, $output, function () use ($id, $permissionPresetClass): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->selectSharePermissionPreset($this->accessContext, $share, $permissionPresetClass); }); diff --git a/apps/sharing/lib/Command/SharingBase.php b/apps/sharing/lib/Command/SharingBase.php index 1ebdb77e9d493..b7395b52df1c6 100644 --- a/apps/sharing/lib/Command/SharingBase.php +++ b/apps/sharing/lib/Command/SharingBase.php @@ -22,6 +22,8 @@ use OCP\IUserManager; use OCP\L10N\IFactory; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -40,10 +42,28 @@ public function __construct( $this->accessContext = new ShareAccessContext(overrideChecks: true); } + #[\Override] + public function configure(): void { + $this + ->addOption('actor', null, InputOption::VALUE_REQUIRED, 'User ID to use as the actor for any share modification'); + parent::configure(); + } + + protected function applyActor(InputInterface $input): void { + /** @var ?string $actorId */ + $actorId = $input->getOption('actor'); + + if ($actorId !== null) { + $actor = $this->userManager->get($actorId); + $this->accessContext = new ShareAccessContext(currentUser: $actor, overrideChecks: true); + } + } + /** * @param Closure():Share $closure */ - protected function wrapExecution(OutputInterface $output, Closure $closure): int { + protected function wrapExecution(InputInterface $input, OutputInterface $output, Closure $closure): int { + $this->applyActor($input); try { try { diff --git a/apps/sharing/lib/Command/UpdateSharePermission.php b/apps/sharing/lib/Command/UpdateSharePermission.php index 4eb632ff2f626..d7b0067715269 100644 --- a/apps/sharing/lib/Command/UpdateSharePermission.php +++ b/apps/sharing/lib/Command/UpdateSharePermission.php @@ -25,6 +25,7 @@ public function configure(): void { ->addArgument('id', InputArgument::REQUIRED, 'Share ID') ->addArgument('class', InputArgument::REQUIRED, 'Permission class') ->addArgument('enabled', InputArgument::REQUIRED, 'Permission enabled. Only takes "true" or "false".'); + parent::configure(); } #[\Override] @@ -37,7 +38,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { $enabled = $input->getArgument('enabled'); $enabled = $enabled === 'true'; - return $this->wrapExecution($output, function () use ($id, $class, $enabled): Share { + return $this->wrapExecution($input, $output, function () use ($id, $class, $enabled): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->updateSharePermission($this->accessContext, $share, new SharePermission($class, $enabled)); }); diff --git a/apps/sharing/lib/Command/UpdateShareProperty.php b/apps/sharing/lib/Command/UpdateShareProperty.php index f8b08c2f71e9a..b197355e5037a 100644 --- a/apps/sharing/lib/Command/UpdateShareProperty.php +++ b/apps/sharing/lib/Command/UpdateShareProperty.php @@ -25,6 +25,7 @@ public function configure(): void { ->addArgument('id', InputArgument::REQUIRED, 'Share ID') ->addArgument('class', InputArgument::REQUIRED, 'Property class') ->addArgument('value', InputArgument::OPTIONAL, 'Property value. Omitting it will remove the value.'); + parent::configure(); } #[\Override] @@ -36,7 +37,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var ?string $value */ $value = $input->getArgument('value'); - return $this->wrapExecution($output, function () use ($id, $class, $value): Share { + return $this->wrapExecution($input, $output, function () use ($id, $class, $value): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->updateShareProperty($this->accessContext, $share, new ShareProperty($class, $value)); }); diff --git a/apps/sharing/lib/Command/UpdateShareRecipientSecret.php b/apps/sharing/lib/Command/UpdateShareRecipientSecret.php index 1f43fa99bc47d..bd3e0998640c7 100644 --- a/apps/sharing/lib/Command/UpdateShareRecipientSecret.php +++ b/apps/sharing/lib/Command/UpdateShareRecipientSecret.php @@ -27,6 +27,7 @@ public function configure(): void { ->addArgument('class', InputArgument::REQUIRED, 'Recipient class') ->addArgument('value', InputArgument::REQUIRED, 'Recipient value') ->addArgument('instance', InputArgument::OPTIONAL, 'Recipient instance'); + parent::configure(); } #[\Override] @@ -42,7 +43,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { /** @var non-empty-string $secret */ $secret = $input->getArgument('secret'); - return $this->wrapExecution($output, function () use ($id, $class, $value, $instance, $secret): Share { + return $this->wrapExecution($input, $output, function () use ($id, $class, $value, $instance, $secret): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->updateShareRecipientSecret($this->accessContext, $share, new ShareRecipient($class, $value, $instance), $secret); }); diff --git a/apps/sharing/lib/Command/UpdateShareState.php b/apps/sharing/lib/Command/UpdateShareState.php index eb9a26fd1c49f..ac34b885664a3 100644 --- a/apps/sharing/lib/Command/UpdateShareState.php +++ b/apps/sharing/lib/Command/UpdateShareState.php @@ -23,6 +23,7 @@ public function configure(): void { ->setDescription('Update the state of a share.') ->addArgument('id', InputArgument::REQUIRED, 'Share ID') ->addArgument('state', InputArgument::REQUIRED, 'State'); + parent::configure(); } #[\Override] @@ -33,7 +34,7 @@ public function execute(InputInterface $input, OutputInterface $output): int { $state = $input->getArgument('state'); $state = ShareState::from($state); - return $this->wrapExecution($output, function () use ($id, $state): Share { + return $this->wrapExecution($input, $output, function () use ($id, $state): Share { $share = $this->manager->getShare($this->accessContext, $id); return $this->manager->updateShareState($this->accessContext, $share, $state); }); diff --git a/apps/sharing/tests/Command/CommandTest.php b/apps/sharing/tests/Command/CommandTest.php index 3245541e90b7b..ec637d083c5bc 100644 --- a/apps/sharing/tests/Command/CommandTest.php +++ b/apps/sharing/tests/Command/CommandTest.php @@ -97,6 +97,7 @@ private function runCommand(ShareAccessContext $accessContext, string $class, ar throw new RuntimeException('Command class ' . $class . ' is not allowed to be used unless added to the array.'); } + $options[] = ['actor', null]; $input = $this->createMock(Input::class); $input ->expects($this->exactly(count($arguments)))