diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index aa56959..e7981c9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -51,7 +51,7 @@ parameters: path: src/bundle/Controller/PasswordResetController.php - - message: "#^Call to an undefined method Symfony\\\\Component\\\\Form\\\\FormInterface\\:\\:getClickedButton\\(\\)\\.$#" + message: "#^Call to an undefined method Symfony\\\\Component\\\\Form\\\\FormInterface\\\\:\\:getClickedButton\\(\\)\\.$#" count: 4 path: src/bundle/Controller/UserRegisterController.php diff --git a/src/bundle/Command/UpdateUserCommand.php b/src/bundle/Command/UpdateUserCommand.php new file mode 100644 index 0000000..533b70a --- /dev/null +++ b/src/bundle/Command/UpdateUserCommand.php @@ -0,0 +1,135 @@ +addArgument( + 'user', + InputArgument::REQUIRED, + 'User login', + ); + $this->addOption( + 'password', + null, + InputOption::VALUE_OPTIONAL, + 'New plaintext password (input will be in a "hidden" mode)', + false + ); + $this->addOption( + 'email', + null, + InputOption::VALUE_REQUIRED, + 'New e-mail address', + ); + $this->addOption( + 'enable', + null, + InputOption::VALUE_NONE, + 'Flag enabling the user being updated', + ); + $this->addOption( + 'disable', + null, + InputOption::VALUE_NONE, + 'Flag disabling the user being updated', + ); + } + + protected function interact(InputInterface $input, OutputInterface $output): void + { + $io = new SymfonyStyle($input, $output); + $password = $input->getOption('password'); + + if ($password !== null) { + return; + } + + $password = $io->askHidden('Password (your input will be hidden)'); + $input->setOption('password', $password); + } + + /** + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $userReference = $input->getArgument('user'); + $password = $input->getOption('password'); + $enable = $input->getOption('enable'); + $disable = $input->getOption('disable'); + $email = $input->getOption('email'); + + if (!$password && !$enable && !$disable && $email === null) { + $io->error('No new user data specified, exiting.'); + + return Command::FAILURE; + } + + $user = $this->userService->loadUserByLogin($userReference); + + if ($enable && $disable) { + $io->error('--enable and --disable options cannot be used simultaneously.'); + + return Command::FAILURE; + } + + $userUpdateStruct = new UserUpdateStruct(); + $userUpdateStruct->password = $password; + $userUpdateStruct->email = $email; + $userUpdateStruct->enabled = $this->resolveEnabledFlag($enable, $disable); + + $this->repository->sudo( + function () use ($user, $userUpdateStruct): User { + return $this->userService->updateUser($user, $userUpdateStruct); + } + ); + + $io->success(sprintf( + 'User "%s" was successfully updated.', + $user->getLogin(), + )); + + return Command::SUCCESS; + } + + private function resolveEnabledFlag(bool $enable, bool $disable): ?bool + { + if (!$enable && !$disable) { + return null; + } + + return $enable === true; + } +} diff --git a/tests/bundle/Command/UpdateUserCommandTest.php b/tests/bundle/Command/UpdateUserCommandTest.php new file mode 100644 index 0000000..134c7c7 --- /dev/null +++ b/tests/bundle/Command/UpdateUserCommandTest.php @@ -0,0 +1,87 @@ +setAutoExit(false); + + $command = $application->find('ibexa:user:update-user'); + $this->commandTester = new CommandTester($command); + } + + public function testExecuteWithoutOptionsReturnsFailure(): void + { + $this->commandTester->execute([ + 'user' => 'anonymous', + ]); + + self::assertStringContainsString( + 'No new user data specified, exiting.', + $this->commandTester->getDisplay() + ); + + self::assertSame( + Command::FAILURE, + $this->commandTester->getStatusCode() + ); + } + + public function testExecuteWithEnableAndDisableOptionsReturnsFailure(): void + { + $this->commandTester->execute( + [ + 'user' => 'anonymous', + '--enable' => true, + '--disable' => true, + ], + ); + + self::assertStringContainsString( + '--enable and --disable options cannot be used simultaneously.', + $this->commandTester->getDisplay() + ); + + self::assertSame( + Command::FAILURE, + $this->commandTester->getStatusCode() + ); + } + + public function testExecuteReturnsSuccess(): void + { + $this->commandTester->execute( + [ + 'user' => 'anonymous', + '--password' => true, + '--email' => 'foo@bar.com', + '--enable' => true, + ], + ); + + self::assertStringContainsString( + 'User "anonymous" was successfully updated.', + $this->commandTester->getDisplay() + ); + + $this->commandTester->assertCommandIsSuccessful(); + } +}