From d1e95d48e8c65104019bbdd17decda00691be906 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Sat, 28 Mar 2026 00:57:49 +0100 Subject: [PATCH 1/2] feat(occ): make it possible to add an arbitrary number of users to a group Signed-off-by: Arthur Schiwon --- core/Command/Group/AddUser.php | 38 ++++++++--- tests/Core/Command/Group/AddUserTest.php | 83 ++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 15 deletions(-) diff --git a/core/Command/Group/AddUser.php b/core/Command/Group/AddUser.php index 2a74452949d07..f725b3c91b737 100644 --- a/core/Command/Group/AddUser.php +++ b/core/Command/Group/AddUser.php @@ -34,8 +34,8 @@ protected function configure() { 'group to add the user to' )->addArgument( 'user', - InputArgument::REQUIRED, - 'user to add to the group' + InputArgument::REQUIRED + InputArgument::IS_ARRAY, + 'users to add to the group', ); } @@ -43,15 +43,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int $group = $this->groupManager->get($input->getArgument('group')); if (is_null($group)) { $output->writeln('group not found'); - return 1; + return Base::FAILURE; + } + + $allUsersFound = true; + $noUserFound = true; + $users = (array)$input->getArgument('user'); + foreach ($users as $userId) { + $user = $this->userManager->get($userId); + if (is_null($user)) { + $output->writeln('user ' . $userId . ' not found'); + $allUsersFound = false; + continue; + } + $noUserFound = false; + $group->addUser($user); + unset($user); + $output->writeln('user ' . $userId . ' added'); } - $user = $this->userManager->get($input->getArgument('user')); - if (is_null($user)) { - $output->writeln('user not found'); - return 1; + + if (!$allUsersFound && !$noUserFound) { + $output->writeln('Some users were not found, all others where added to the group.'); + return Base::FAILURE; + } + + if ($noUserFound) { + return Base::FAILURE; } - $group->addUser($user); - return 0; + + return Base::SUCCESS; } /** diff --git a/tests/Core/Command/Group/AddUserTest.php b/tests/Core/Command/Group/AddUserTest.php index 68c8cecdba128..e52f737c47c69 100644 --- a/tests/Core/Command/Group/AddUserTest.php +++ b/tests/Core/Command/Group/AddUserTest.php @@ -38,21 +38,26 @@ protected function setUp(): void { $this->groupManager = $this->createMock(IGroupManager::class); $this->userManager = $this->createMock(IUserManager::class); $this->command = new AddUser($this->userManager, $this->groupManager); + $this->output = $this->createMock(OutputInterface::class); + } + protected function configureInput(array|string $returnGroup, array|string $returnUser): void { $this->input = $this->createMock(InputInterface::class); $this->input->method('getArgument') - ->willReturnCallback(function ($arg) { + ->willReturnCallback(function ($arg) use ($returnGroup, $returnUser) { if ($arg === 'group') { - return 'myGroup'; - } elseif ($arg === 'user') { - return 'myUser'; + return $returnGroup; + } + if ($arg === 'user') { + return $returnUser; } throw new \Exception(); }); - $this->output = $this->createMock(OutputInterface::class); } public function testNoGroup(): void { + $this->configureInput('myGroup', 'myUser'); + $this->groupManager->method('get') ->with('myGroup') ->willReturn(null); @@ -65,6 +70,8 @@ public function testNoGroup(): void { } public function testNoUser(): void { + $this->configureInput('myGroup', 'myUser'); + $group = $this->createMock(IGroup::class); $this->groupManager->method('get') ->with('myGroup') @@ -76,12 +83,14 @@ public function testNoUser(): void { $this->output->expects($this->once()) ->method('writeln') - ->with('user not found'); + ->with('user myUser not found'); $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); } public function testAdd(): void { + $this->configureInput('myGroup', 'myUser'); + $group = $this->createMock(IGroup::class); $this->groupManager->method('get') ->with('myGroup') @@ -98,4 +107,66 @@ public function testAdd(): void { $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); } + + public function testAddMultiple(): void { + $this->configureInput('myGroup', ['myUser', 'myOtherUser']); + + $group = $this->createMock(IGroup::class); + $this->groupManager->method('get') + ->with('myGroup') + ->willReturn($group); + + $user1 = $this->createMock(IUser::class); + $user2 = $this->createMock(IUser::class); + $this->userManager->method('get') + ->willReturnMap([ + ['myUser', $user1], + ['myOtherUser', $user2], + ]); + + $group->expects($this->exactly(2)) + ->method('addUser') + ->with($this->callback(static fn (IUser $user): bool => in_array($user, [$user1, $user2], true))); + + $this->output->expects($this->exactly(2)) + ->method('writeln') + ->with($this->callback(static fn (string $message): bool => in_array($message, + [ + 'user myUser added', + 'user myOtherUser added', + ], true))); + + $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); + } + + public function testAddMultiplePartialSuccess(): void { + $this->configureInput('myGroup', ['myUser', 'myOtherUser']); + + $group = $this->createMock(IGroup::class); + $this->groupManager->method('get') + ->with('myGroup') + ->willReturn($group); + + $user = $this->createMock(IUser::class); + $this->userManager->method('get') + ->willReturnMap([ + ['myUser', $user], + ['myOtherUser', null], + ]); + + $group->expects($this->once()) + ->method('addUser') + ->with($user); + + $this->output->expects($this->exactly(3)) + ->method('writeln') + ->with($this->callback(static fn (string $message): bool => in_array($message, + [ + 'user myUser added', + 'user myOtherUser not found', + 'Some users were not found, all others where added to the group.', + ], true))); + + $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); + } } From bb43721f6100ff88fa146d2aa88c07e3db1be3da Mon Sep 17 00:00:00 2001 From: "Enjeck C." Date: Thu, 9 Apr 2026 21:16:52 +0100 Subject: [PATCH 2/2] feat(occ): make it possible to remove an arbitrary number of users to a group Signed-off-by: Enjeck C. --- core/Command/Group/RemoveUser.php | 38 ++++++--- tests/Core/Command/Group/RemoveUserTest.php | 85 +++++++++++++++++++-- 2 files changed, 107 insertions(+), 16 deletions(-) diff --git a/core/Command/Group/RemoveUser.php b/core/Command/Group/RemoveUser.php index 952fc6e77127c..a7da59e5c924f 100644 --- a/core/Command/Group/RemoveUser.php +++ b/core/Command/Group/RemoveUser.php @@ -34,8 +34,8 @@ protected function configure() { 'group to remove the user from' )->addArgument( 'user', - InputArgument::REQUIRED, - 'user to remove from the group' + InputArgument::REQUIRED + InputArgument::IS_ARRAY, + 'users to remove from the group' ); } @@ -43,15 +43,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int $group = $this->groupManager->get($input->getArgument('group')); if (is_null($group)) { $output->writeln('group not found'); - return 1; + return Base::FAILURE; + } + + $allUsersFound = true; + $noUserFound = true; + $users = (array)$input->getArgument('user'); + foreach ($users as $userId) { + $user = $this->userManager->get($userId); + if (is_null($user)) { + $output->writeln('user ' . $userId . ' not found'); + $allUsersFound = false; + continue; + } + $noUserFound = false; + $group->removeUser($user); + unset($user); + $output->writeln('user ' . $userId . ' removed'); } - $user = $this->userManager->get($input->getArgument('user')); - if (is_null($user)) { - $output->writeln('user not found'); - return 1; + + if (!$allUsersFound && !$noUserFound) { + $output->writeln('Some users were not found, all others where removed from the group.'); + return Base::FAILURE; + } + + if ($noUserFound) { + return Base::FAILURE; } - $group->removeUser($user); - return 0; + + return Base::SUCCESS; } /** diff --git a/tests/Core/Command/Group/RemoveUserTest.php b/tests/Core/Command/Group/RemoveUserTest.php index 74343e77d3fae..6ecd4068d1496 100644 --- a/tests/Core/Command/Group/RemoveUserTest.php +++ b/tests/Core/Command/Group/RemoveUserTest.php @@ -38,21 +38,26 @@ protected function setUp(): void { $this->groupManager = $this->createMock(IGroupManager::class); $this->userManager = $this->createMock(IUserManager::class); $this->command = new RemoveUser($this->userManager, $this->groupManager); + $this->output = $this->createMock(OutputInterface::class); + } + protected function configureInput(array|string $returnGroup, array|string $returnUser): void { $this->input = $this->createMock(InputInterface::class); $this->input->method('getArgument') - ->willReturnCallback(function ($arg) { + ->willReturnCallback(function ($arg) use ($returnGroup, $returnUser) { if ($arg === 'group') { - return 'myGroup'; - } elseif ($arg === 'user') { - return 'myUser'; + return $returnGroup; + } + if ($arg === 'user') { + return $returnUser; } throw new \Exception(); }); - $this->output = $this->createMock(OutputInterface::class); } public function testNoGroup(): void { + $this->configureInput('myGroup', 'myUser'); + $this->groupManager->method('get') ->with('myGroup') ->willReturn(null); @@ -65,6 +70,8 @@ public function testNoGroup(): void { } public function testNoUser(): void { + $this->configureInput('myGroup', 'myUser'); + $group = $this->createMock(IGroup::class); $this->groupManager->method('get') ->with('myGroup') @@ -76,12 +83,14 @@ public function testNoUser(): void { $this->output->expects($this->once()) ->method('writeln') - ->with('user not found'); + ->with('user myUser not found'); $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); } - public function testAdd(): void { + public function testRemove(): void { + $this->configureInput('myGroup', 'myUser'); + $group = $this->createMock(IGroup::class); $this->groupManager->method('get') ->with('myGroup') @@ -98,4 +107,66 @@ public function testAdd(): void { $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); } + + public function testRemoveMultiple(): void { + $this->configureInput('myGroup', ['myUser', 'myOtherUser']); + + $group = $this->createMock(IGroup::class); + $this->groupManager->method('get') + ->with('myGroup') + ->willReturn($group); + + $user1 = $this->createMock(IUser::class); + $user2 = $this->createMock(IUser::class); + $this->userManager->method('get') + ->willReturnMap([ + ['myUser', $user1], + ['myOtherUser', $user2], + ]); + + $group->expects($this->exactly(2)) + ->method('removeUser') + ->with($this->callback(static fn (IUser $user): bool => in_array($user, [$user1, $user2], true))); + + $this->output->expects($this->exactly(2)) + ->method('writeln') + ->with($this->callback(static fn (string $message): bool => in_array($message, + [ + 'user myUser removed', + 'user myOtherUser removed', + ], true))); + + $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); + } + + public function testRemoveMultiplePartialSuccess(): void { + $this->configureInput('myGroup', ['myUser', 'myOtherUser']); + + $group = $this->createMock(IGroup::class); + $this->groupManager->method('get') + ->with('myGroup') + ->willReturn($group); + + $user = $this->createMock(IUser::class); + $this->userManager->method('get') + ->willReturnMap([ + ['myUser', $user], + ['myOtherUser', null], + ]); + + $group->expects($this->once()) + ->method('removeUser') + ->with($user); + + $this->output->expects($this->exactly(3)) + ->method('writeln') + ->with($this->callback(static fn (string $message): bool => in_array($message, + [ + 'user myUser removed', + 'user myOtherUser not found', + 'Some users were not found, all others where removed from the group.', + ], true))); + + $this->invokePrivate($this->command, 'execute', [$this->input, $this->output]); + } }