From 7681fa2aff431e1e5b809e24863e7c784404e8d0 Mon Sep 17 00:00:00 2001 From: Benjamin Gaussorgues Date: Wed, 6 Dec 2023 16:16:30 +0100 Subject: [PATCH] feat(settings): add occ commands to handle admin delegation Signed-off-by: Benjamin Gaussorgues --- apps/settings/appinfo/info.xml | 8 +- .../composer/composer/autoload_classmap.php | 3 + .../composer/composer/autoload_static.php | 3 + .../lib/Command/AdminDelegation/Add.php | 76 +++++++++++++++ .../lib/Command/AdminDelegation/Remove.php | 72 ++++++++++++++ .../lib/Command/AdminDelegation/Show.php | 94 +++++++++++++++++++ 6 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 apps/settings/lib/Command/AdminDelegation/Add.php create mode 100644 apps/settings/lib/Command/AdminDelegation/Remove.php create mode 100644 apps/settings/lib/Command/AdminDelegation/Show.php diff --git a/apps/settings/appinfo/info.xml b/apps/settings/appinfo/info.xml index fefa2fadaeffe..a758b8e6af4db 100644 --- a/apps/settings/appinfo/info.xml +++ b/apps/settings/appinfo/info.xml @@ -5,7 +5,7 @@ Nextcloud settings Nextcloud settings Nextcloud settings - 1.10.0 + 1.10.1 agpl Nextcloud Settings @@ -16,6 +16,12 @@ + + OCA\Settings\Command\AdminDelegation\Show + OCA\Settings\Command\AdminDelegation\Add + OCA\Settings\Command\AdminDelegation\Remove + + OCA\Settings\Settings\Admin\Mail OCA\Settings\Settings\Admin\Overview diff --git a/apps/settings/composer/composer/autoload_classmap.php b/apps/settings/composer/composer/autoload_classmap.php index 6dbc2518219c8..835cec75cd2aa 100644 --- a/apps/settings/composer/composer/autoload_classmap.php +++ b/apps/settings/composer/composer/autoload_classmap.php @@ -16,6 +16,9 @@ 'OCA\\Settings\\Activity\\Setting' => $baseDir . '/../lib/Activity/Setting.php', 'OCA\\Settings\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php', 'OCA\\Settings\\BackgroundJobs\\VerifyUserData' => $baseDir . '/../lib/BackgroundJobs/VerifyUserData.php', + 'OCA\\Settings\\Command\\AdminDelegation\\Add' => $baseDir . '/../lib/Command/AdminDelegation/Add.php', + 'OCA\\Settings\\Command\\AdminDelegation\\Remove' => $baseDir . '/../lib/Command/AdminDelegation/Remove.php', + 'OCA\\Settings\\Command\\AdminDelegation\\Show' => $baseDir . '/../lib/Command/AdminDelegation/Show.php', 'OCA\\Settings\\Controller\\AISettingsController' => $baseDir . '/../lib/Controller/AISettingsController.php', 'OCA\\Settings\\Controller\\AdminSettingsController' => $baseDir . '/../lib/Controller/AdminSettingsController.php', 'OCA\\Settings\\Controller\\AppSettingsController' => $baseDir . '/../lib/Controller/AppSettingsController.php', diff --git a/apps/settings/composer/composer/autoload_static.php b/apps/settings/composer/composer/autoload_static.php index c05f58ac45917..649690a5dad26 100644 --- a/apps/settings/composer/composer/autoload_static.php +++ b/apps/settings/composer/composer/autoload_static.php @@ -31,6 +31,9 @@ class ComposerStaticInitSettings 'OCA\\Settings\\Activity\\Setting' => __DIR__ . '/..' . '/../lib/Activity/Setting.php', 'OCA\\Settings\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php', 'OCA\\Settings\\BackgroundJobs\\VerifyUserData' => __DIR__ . '/..' . '/../lib/BackgroundJobs/VerifyUserData.php', + 'OCA\\Settings\\Command\\AdminDelegation\\Add' => __DIR__ . '/..' . '/../lib/Command/AdminDelegation/Add.php', + 'OCA\\Settings\\Command\\AdminDelegation\\Remove' => __DIR__ . '/..' . '/../lib/Command/AdminDelegation/Remove.php', + 'OCA\\Settings\\Command\\AdminDelegation\\Show' => __DIR__ . '/..' . '/../lib/Command/AdminDelegation/Show.php', 'OCA\\Settings\\Controller\\AISettingsController' => __DIR__ . '/..' . '/../lib/Controller/AISettingsController.php', 'OCA\\Settings\\Controller\\AdminSettingsController' => __DIR__ . '/..' . '/../lib/Controller/AdminSettingsController.php', 'OCA\\Settings\\Controller\\AppSettingsController' => __DIR__ . '/..' . '/../lib/Controller/AppSettingsController.php', diff --git a/apps/settings/lib/Command/AdminDelegation/Add.php b/apps/settings/lib/Command/AdminDelegation/Add.php new file mode 100644 index 0000000000000..c721dc2a9d0cd --- /dev/null +++ b/apps/settings/lib/Command/AdminDelegation/Add.php @@ -0,0 +1,76 @@ + + * + * @author Benjamin Gaussorgues + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + * + */ +namespace OCA\Settings\Command\AdminDelegation; + +use OC\Core\Command\Base; +use OCA\Settings\Service\AuthorizedGroupService; +use OCP\IGroupManager; +use OCP\Settings\IDelegatedSettings; +use OCP\Settings\IManager; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +class Add extends Base { + public function __construct( + private IManager $settingManager, + private AuthorizedGroupService $authorizedGroupService, + private IGroupManager $groupManager, + ) { + parent::__construct(); + } + + protected function configure(): void { + $this + ->setName('admin-delegation:add') + ->setDescription('add setting delegation to a group') + ->addArgument('settingClass', InputArgument::REQUIRED, 'Admin setting class') + ->addArgument('groupId', InputArgument::REQUIRED, 'Delegate to group ID') + ->addUsage('\'OCA\Settings\Settings\Admin\Server\' mygroup') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $io = new SymfonyStyle($input, $output); + $settingClass = $input->getArgument('settingClass'); + if (!in_array(IDelegatedSettings::class, (array) class_implements($settingClass), true)) { + $io->error('The specified class isn’t a valid delegated setting.'); + return 2; + } + + $groupId = $input->getArgument('groupId'); + if (!$this->groupManager->groupExists($groupId)) { + $io->error('The specified group didn’t exist.'); + return 3; + } + + $this->authorizedGroupService->create($groupId, $settingClass); + + $io->success('Administration of '.$settingClass.' delegated to '.$groupId.'.'); + + return 0; + } +} diff --git a/apps/settings/lib/Command/AdminDelegation/Remove.php b/apps/settings/lib/Command/AdminDelegation/Remove.php new file mode 100644 index 0000000000000..f6e3e827ff67b --- /dev/null +++ b/apps/settings/lib/Command/AdminDelegation/Remove.php @@ -0,0 +1,72 @@ + + * + * @author Benjamin Gaussorgues + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + * + */ +namespace OCA\Settings\Command\AdminDelegation; + +use OC\Core\Command\Base; +use OCA\Settings\Service\AuthorizedGroupService; +use OCP\IGroupManager; +use OCP\Settings\IManager; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +class Remove extends Base { + public function __construct( + private IManager $settingManager, + private AuthorizedGroupService $authorizedGroupService, + private IGroupManager $groupManager, + ) { + parent::__construct(); + } + + protected function configure(): void { + $this + ->setName('admin-delegation:remove') + ->setDescription('remove settings delegation from a group') + ->addArgument('settingClass', InputArgument::REQUIRED, 'Admin setting class') + ->addArgument('groupId', InputArgument::REQUIRED, 'Group ID to remove') + ->addUsage('\'OCA\Settings\Settings\Admin\Server\' mygroup') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $io = new SymfonyStyle($input, $output); + $settingClass = $input->getArgument('settingClass'); + $groups = $this->authorizedGroupService->findExistingGroupsForClass($settingClass); + $groupId = $input->getArgument('groupId'); + foreach ($groups as $group) { + if ($group->getGroupId() === $groupId) { + $this->authorizedGroupService->delete($group->getId()); + $io->success('Removed delegation of '.$settingClass.' to '.$groupId.'.'); + return 0; + } + } + + $io->success('Group '.$groupId.' didn’t have delegation for '.$settingClass.'.'); + + return 0; + } +} diff --git a/apps/settings/lib/Command/AdminDelegation/Show.php b/apps/settings/lib/Command/AdminDelegation/Show.php new file mode 100644 index 0000000000000..8ef2314c0dc59 --- /dev/null +++ b/apps/settings/lib/Command/AdminDelegation/Show.php @@ -0,0 +1,94 @@ + + * + * @author Benjamin Gaussorgues + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + * + */ +namespace OCA\Settings\Command\AdminDelegation; + +use OC\Core\Command\Base; +use OC\Settings\AuthorizedGroup; +use OCA\Settings\Service\AuthorizedGroupService; +use OCP\Settings\IDelegatedSettings; +use OCP\Settings\IManager; +use OCP\Settings\ISettings; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +class Show extends Base { + public function __construct( + private IManager $settingManager, + private AuthorizedGroupService $authorizedGroupService, + ) { + parent::__construct(); + } + + protected function configure(): void { + $this + ->setName('admin-delegation:show') + ->setDescription('show delegated settings') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $io = new SymfonyStyle($input, $output); + $io->title('Current delegations'); + + $sections = $this->settingManager->getAdminSections(); + $settings = []; + $headers = ['Name', 'SettingId', 'Delegated to groups']; + foreach ($sections as $sectionPriority) { + foreach ($sectionPriority as $section) { + $sectionSettings = $this->settingManager->getAdminSettings($section->getId()); + $sectionSettings = array_reduce($sectionSettings, [$this, 'getDelegatedSettings'], []); + if (empty($sectionSettings)) { + continue; + } + + $io->section('Section: '.$section->getID()); + $io->table($headers, array_map(function (IDelegatedSettings $setting) use ($section) { + $className = get_class($setting); + $groups = array_map( + static fn (AuthorizedGroup $group) => $group->getGroupId(), + $this->authorizedGroupService->findExistingGroupsForClass($className) + ); + natsort($groups); + return [ + $setting->getName() ?: 'Global', + $className, + implode(', ', $groups), + ]; + }, $sectionSettings)); + } + } + + return 0; + } + + /** + * @param IDelegatedSettings[] $settings + * @param array $innerSection + */ + private function getDelegatedSettings(array $settings, array $innerSection): array { + return $settings + array_filter($innerSection, fn (ISettings $setting) => $setting instanceof IDelegatedSettings); + } +}