This makes it possible for selected groups to access some settings pages. Signed-off-by: Carl Schwan <carl@carlschwan.eu>pull/28189/head
parent
ee987d7430
commit
6958d8005a
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,80 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
namespace OCA\Settings\Controller; |
||||
|
||||
use OC\Settings\AuthorizedGroup; |
||||
use OCA\Settings\Service\AuthorizedGroupService; |
||||
use OCA\Settings\Service\NotFoundException; |
||||
use OCP\DB\Exception; |
||||
use OCP\IRequest; |
||||
use OCP\AppFramework\Http\DataResponse; |
||||
use OCP\AppFramework\Controller; |
||||
|
||||
class AuthorizedGroupController extends Controller { |
||||
/** @var AuthorizedGroupService $authorizedGroupService */ |
||||
private $authorizedGroupService; |
||||
|
||||
public function __construct(string $AppName, IRequest $request, AuthorizedGroupService $authorizedGroupService) { |
||||
parent::__construct($AppName, $request); |
||||
$this->authorizedGroupService = $authorizedGroupService; |
||||
} |
||||
|
||||
/** |
||||
* @throws NotFoundException |
||||
* @throws Exception |
||||
*/ |
||||
public function saveSettings(array $newGroups, string $class): DataResponse { |
||||
$currentGroups = $this->authorizedGroupService->findExistingGroupsForClass($class); |
||||
|
||||
foreach ($currentGroups as $group) { |
||||
/** @var AuthorizedGroup $group */ |
||||
$removed = true; |
||||
foreach ($newGroups as $groupData) { |
||||
if ($groupData['gid'] === $group->getGroupId()) { |
||||
$removed = false; |
||||
break; |
||||
} |
||||
} |
||||
if ($removed) { |
||||
$this->authorizedGroupService->delete($group->getId()); |
||||
} |
||||
} |
||||
|
||||
foreach ($newGroups as $groupData) { |
||||
$added = true; |
||||
foreach ($currentGroups as $group) { |
||||
/** @var AuthorizedGroup $group */ |
||||
if ($groupData['gid'] === $group->getGroupId()) { |
||||
$added = false; |
||||
break; |
||||
} |
||||
} |
||||
if ($added) { |
||||
$this->authorizedGroupService->create($groupData['gid'], $class); |
||||
} |
||||
} |
||||
|
||||
return new DataResponse(['valid' => true]); |
||||
} |
||||
} |
@ -0,0 +1,51 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\Settings\Listener; |
||||
|
||||
use OCA\Settings\Service\AuthorizedGroupService; |
||||
use OCP\EventDispatcher\Event; |
||||
use OCP\EventDispatcher\IEventListener; |
||||
use OCP\Group\Events\GroupDeletedEvent; |
||||
|
||||
class GroupRemovedListener implements IEventListener { |
||||
|
||||
/** @var AuthorizedGroupService $authorizedGroupService */ |
||||
private $authorizedGroupService; |
||||
|
||||
public function __construct(AuthorizedGroupService $authorizedGroupService) { |
||||
$this->authorizedGroupService = $authorizedGroupService; |
||||
} |
||||
|
||||
/** |
||||
* @inheritDoc |
||||
*/ |
||||
public function handle(Event $event): void { |
||||
if (!($event instanceof GroupDeletedEvent)) { |
||||
return; |
||||
} |
||||
|
||||
/** @var GroupDeletedEvent $event */ |
||||
$this->authorizedGroupService->removeAuthorizationAssociatedTo($event->getGroup()); |
||||
} |
||||
} |
@ -0,0 +1,76 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2021 Nextcloud GmbH |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\Settings\Sections\Admin; |
||||
|
||||
use OCP\IL10N; |
||||
use OCP\IURLGenerator; |
||||
use OCP\Settings\IIconSection; |
||||
|
||||
class Delegation implements IIconSection { |
||||
/** @var IL10N */ |
||||
private $l; |
||||
/** @var IURLGenerator */ |
||||
private $url; |
||||
|
||||
/** |
||||
* @param IURLGenerator $url |
||||
* @param IL10N $l |
||||
*/ |
||||
public function __construct(IURLGenerator $url, IL10N $l) { |
||||
$this->url = $url; |
||||
$this->l = $l; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* @return string |
||||
*/ |
||||
public function getID() { |
||||
return 'admindelegation'; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* @return string |
||||
*/ |
||||
public function getName() { |
||||
return $this->l->t('Admin right privilege'); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* @return int |
||||
*/ |
||||
public function getPriority() { |
||||
return 54; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
* @return string |
||||
*/ |
||||
public function getIcon() { |
||||
return $this->url->imagePath('core', 'places/contacts.svg'); |
||||
} |
||||
} |
@ -0,0 +1,116 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021 Nextcloud GmbH |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\Settings\Service; |
||||
|
||||
use OCP\AppFramework\Db\DoesNotExistException; |
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException; |
||||
|
||||
use OC\Settings\AuthorizedGroup; |
||||
use OC\Settings\AuthorizedGroupMapper; |
||||
use OCP\DB\Exception; |
||||
use OCP\IGroup; |
||||
|
||||
class AuthorizedGroupService { |
||||
|
||||
/** @var AuthorizedGroupMapper $mapper */ |
||||
private $mapper; |
||||
|
||||
public function __construct(AuthorizedGroupMapper $mapper) { |
||||
$this->mapper = $mapper; |
||||
} |
||||
|
||||
/** |
||||
* @return AuthorizedGroup[] |
||||
*/ |
||||
public function findAll(): array { |
||||
return $this->mapper->findAll(); |
||||
} |
||||
|
||||
/** |
||||
* Find AuthorizedGroup by id. |
||||
* |
||||
* @param int $id |
||||
*/ |
||||
public function find(int $id): ?AuthorizedGroup { |
||||
return $this->mapper->find($id); |
||||
} |
||||
|
||||
/** |
||||
* @param $e |
||||
* @throws NotFoundException |
||||
*/ |
||||
private function handleException(\Exception $e): void { |
||||
if ($e instanceof DoesNotExistException || |
||||
$e instanceof MultipleObjectsReturnedException) { |
||||
throw new NotFoundException("AuthorizedGroup not found"); |
||||
} else { |
||||
throw $e; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create a new AuthorizedGroup |
||||
* |
||||
* @param string $groupId |
||||
* @param string $class |
||||
* @return AuthorizedGroup |
||||
* @throws Exception |
||||
*/ |
||||
public function create(string $groupId, string $class): AuthorizedGroup { |
||||
$authorizedGroup = new AuthorizedGroup(); |
||||
$authorizedGroup->setGroupId($groupId); |
||||
$authorizedGroup->setClass($class); |
||||
return $this->mapper->insert($authorizedGroup); |
||||
} |
||||
|
||||
/** |
||||
* @throws NotFoundException |
||||
*/ |
||||
public function delete(int $id): void { |
||||
try { |
||||
$authorizedGroup = $this->mapper->find($id); |
||||
$this->mapper->delete($authorizedGroup); |
||||
} catch (\Exception $e) { |
||||
$this->handleException($e); |
||||
} |
||||
} |
||||
|
||||
public function findExistingGroupsForClass(string $class): array { |
||||
try { |
||||
$authorizedGroup = $this->mapper->findExistingGroupsForClass($class); |
||||
return $authorizedGroup; |
||||
} catch (\Exception $e) { |
||||
return []; |
||||
} |
||||
} |
||||
|
||||
public function removeAuthorizationAssociatedTo(IGroup $group): void { |
||||
try { |
||||
$this->mapper->removeGroup($group->getGID()); |
||||
} catch (\Exception $e) { |
||||
$this->handleException($e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
namespace OCA\Settings\Service; |
||||
|
||||
class NotFoundException extends ServiceException { |
||||
} |
@ -0,0 +1,27 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021 Nextcloud GmbH |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
namespace OCA\Settings\Service; |
||||
|
||||
class ServiceException extends \Exception { |
||||
} |
@ -0,0 +1,148 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\Settings\Settings\Admin; |
||||
|
||||
use OCA\Settings\AppInfo\Application; |
||||
use OCA\Settings\Service\AuthorizedGroupService; |
||||
use OCP\AppFramework\Http\TemplateResponse; |
||||
use OCP\AppFramework\Services\IInitialState; |
||||
use OCP\IGroupManager; |
||||
use OCP\Settings\IDelegatedSettings; |
||||
use OCP\Settings\IManager; |
||||
use OCP\Settings\ISettings; |
||||
|
||||
class Delegation implements ISettings { |
||||
/** @var IManager */ |
||||
private $settingManager; |
||||
|
||||
/** @var IInitialState $initialStateService */ |
||||
private $initialStateService; |
||||
|
||||
/** @var IGroupManager $groupManager */ |
||||
private $groupManager; |
||||
|
||||
/** @var AuthorizedGroupService $authorizedGroupService */ |
||||
private $authorizedGroupService; |
||||
|
||||
public function __construct( |
||||
IManager $settingManager, |
||||
IInitialState $initialStateService, |
||||
IGroupManager $groupManager, |
||||
AuthorizedGroupService $authorizedGroupService |
||||
) { |
||||
$this->settingManager = $settingManager; |
||||
$this->initialStateService = $initialStateService; |
||||
$this->groupManager = $groupManager; |
||||
$this->authorizedGroupService = $authorizedGroupService; |
||||
} |
||||
|
||||
/** |
||||
* Filter out the ISettings that are not IDelegatedSettings from $innerSection |
||||
* and add them to $settings. |
||||
* |
||||
* @param IDelegatedSettings[] $settings |
||||
* @param ISettings[] $innerSection |
||||
* @return IDelegatedSettings[] |
||||
*/ |
||||
private function getDelegatedSettings(array $settings, array $innerSection): array { |
||||
foreach ($innerSection as $setting) { |
||||
if ($setting instanceof IDelegatedSettings) { |
||||
$settings[] = $setting; |
||||
} |
||||
} |
||||
return $settings; |
||||
} |
||||
|
||||
private function initSettingState(): void { |
||||
// Available settings page initialization |
||||
$sections = $this->settingManager->getAdminSections(); |
||||
$settings = []; |
||||
foreach ($sections as $sectionPriority) { |
||||
foreach ($sectionPriority as $section) { |
||||
$sectionSettings = $this->settingManager->getAdminSettings($section->getId()); |
||||
$sectionSettings = array_reduce($sectionSettings, [$this, 'getDelegatedSettings'], []); |
||||
$settings = array_merge( |
||||
$settings, |
||||
array_map(function (IDelegatedSettings $setting) use ($section) { |
||||
return [ |
||||
'class' => get_class($setting), |
||||
'sectionName' => $section->getName() . ($setting->getName() !== null ? ' - ' . $setting->getName() : ''), |
||||
'priority' => $section->getPriority(), |
||||
]; |
||||
}, $sectionSettings) |
||||
); |
||||
} |
||||
} |
||||
usort($settings, function (array $a, array $b) { |
||||
if ($a['priority'] == $b['priority']) { |
||||
return 0; |
||||
} |
||||
return ($a['priority'] < $b['priority']) ? -1 : 1; |
||||
}); |
||||
$this->initialStateService->provideInitialState('available-settings', $settings); |
||||
} |
||||
|
||||
public function initAvailableGroupState(): void { |
||||
// Available groups initialization |
||||
$groups = []; |
||||
$groupsClass = $this->groupManager->search(''); |
||||
foreach ($groupsClass as $group) { |
||||
if ($group->getGID() === 'admin') { |
||||
continue; // Admin already have access to everything |
||||
} |
||||
$groups[] = [ |
||||
'displayName' => $group->getDisplayName(), |
||||
'gid' => $group->getGID(), |
||||
]; |
||||
} |
||||
$this->initialStateService->provideInitialState('available-groups', $groups); |
||||
} |
||||
|
||||
public function initAuthorizedGroupState(): void { |
||||
// Already set authorized groups |
||||
$this->initialStateService->provideInitialState('authorized-groups', $this->authorizedGroupService->findAll()); |
||||
} |
||||
|
||||
public function getForm(): TemplateResponse { |
||||
$this->initSettingState(); |
||||
$this->initAvailableGroupState(); |
||||
$this->initAuthorizedGroupState(); |
||||
|
||||
return new TemplateResponse(Application::APP_ID, 'settings/admin/delegation', [], ''); |
||||
} |
||||
|
||||
/** |
||||
* @return string the section ID, e.g. 'sharing' |
||||
*/ |
||||
public function getSection() { |
||||
return 'admindelegation'; |
||||
} |
||||
|
||||
/* |
||||
* @inheritdoc |
||||
*/ |
||||
public function getPriority() { |
||||
return 75; |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
<template> |
||||
<div id="admin-right-sub-granting" class="section"> |
||||
<h2>{{ t('settings', 'Admin right privilege') }}</h2> |
||||
<p class="settings-hint"> |
||||
{{ t('settings', 'Here you can decide which group can access some of the admin settings.') }} |
||||
</p> |
||||
|
||||
<div class="setting-list"> |
||||
<div v-for="setting in availableSettings" :key="setting.class"> |
||||
<h3>{{ setting.sectionName }}</h3> |
||||
<GroupSelect :available-groups="availableGroups" :authorized-groups="authorizedGroups" :setting="setting" /> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import GroupSelect from './AdminDelegation/GroupSelect' |
||||
import { loadState } from '@nextcloud/initial-state' |
||||
|
||||
export default { |
||||
name: 'AdminDelegating', |
||||
components: { |
||||
GroupSelect, |
||||
}, |
||||
data() { |
||||
const availableSettings = loadState('settings', 'available-settings') |
||||
const availableGroups = loadState('settings', 'available-groups') |
||||
const authorizedGroups = loadState('settings', 'authorized-groups') |
||||
return { |
||||
availableSettings, |
||||
availableGroups, |
||||
authorizedGroups, |
||||
} |
||||
}, |
||||
} |
||||
</script> |
@ -0,0 +1,75 @@ |
||||
<template> |
||||
<Multiselect |
||||
v-model="selected" |
||||
class="group-multiselect" |
||||
:placeholder="t('settings', 'None')" |
||||
track-by="gid" |
||||
label="displayName" |
||||
:options="availableGroups" |
||||
open-direction="bottom" |
||||
:multiple="true" |
||||
:allow-empty="true" /> |
||||
</template> |
||||
|
||||
<script> |
||||
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect' |
||||
import { generateUrl } from '@nextcloud/router' |
||||
import axios from '@nextcloud/axios' |
||||
import { showError } from '@nextcloud/dialogs' |
||||
import logger from '../../logger' |
||||
|
||||
export default { |
||||
name: 'GroupSelect', |
||||
components: { |
||||
Multiselect, |
||||
}, |
||||
props: { |
||||
availableGroups: { |
||||
type: Array, |
||||
default: () => [], |
||||
}, |
||||
setting: { |
||||
type: Object, |
||||
required: true, |
||||
}, |
||||
authorizedGroups: { |
||||
type: Array, |
||||
required: true, |
||||
}, |
||||
}, |
||||
data() { |
||||
return { |
||||
selected: this.authorizedGroups |
||||
.filter((group) => group.class === this.setting.class) |
||||
.map((groupToMap) => this.availableGroups.find((group) => group.gid === groupToMap.group_id)) |
||||
.filter((group) => group !== undefined) |
||||
} |
||||
}, |
||||
watch: { |
||||
selected() { |
||||
this.saveGroups() |
||||
}, |
||||
}, |
||||
methods: { |
||||
async saveGroups() { |
||||
const data = { |
||||
newGroups: this.selected, |
||||
class: this.setting.class, |
||||
} |
||||
try { |
||||
await axios.post(generateUrl('/apps/settings/') + '/settings/authorizedgroups/saveSettings', data) |
||||
} catch (e) { |
||||
showError(t('settings', 'Unable to modify setting')) |
||||
logger.error('Unable to modify setting', e) |
||||
} |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.group-multiselect { |
||||
width: 100%; |
||||
margin-right: 0; |
||||
} |
||||
</style> |
@ -0,0 +1,32 @@ |
||||
/** |
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
|
||||
import Vue from 'vue' |
||||
import App from './components/AdminDelegating.vue' |
||||
|
||||
// bind to window
|
||||
Vue.prototype.OC = OC |
||||
Vue.prototype.t = t |
||||
|
||||
const View = Vue.extend(App) |
||||
const accessibility = new View() |
||||
accessibility.$mount('#admin-right-sub-granting') |
@ -0,0 +1,29 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021 Nextcloud GmbH |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
script('settings', 'vue-settings-admin-delegation'); |
||||
?> |
||||
|
||||
<div id="admin-right-sub-granting"> |
||||
</div> |
@ -0,0 +1,77 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2021 Nextcloud GmbH |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
|
||||
namespace OCA\Settings\Tests\Controller\Admin; |
||||
|
||||
use OC\Settings\AuthorizedGroup; |
||||
use OCA\Settings\Controller\AuthorizedGroupController; |
||||
use OCA\Settings\Service\AuthorizedGroupService; |
||||
use OCP\IRequest; |
||||
use Test\TestCase; |
||||
|
||||
class DelegationControllerTest extends TestCase { |
||||
|
||||
/** @var AuthorizedGroupService */ |
||||
private $service; |
||||
|
||||
/** @var IRequest */ |
||||
private $request; |
||||
|
||||
/** @var AuthorizedGroupController */ |
||||
private $controller; |
||||
|
||||
protected function setUp(): void { |
||||
parent::setUp(); |
||||
$this->request = $this->getMockBuilder(IRequest::class)->getMock(); |
||||
$this->service = $this->getMockBuilder(AuthorizedGroupService::class)->disableOriginalConstructor()->getMock(); |
||||
$this->controller = new AuthorizedGroupController( |
||||
'settings', $this->request, $this->service |
||||
); |
||||
} |
||||
|
||||
public function testSaveSettings() { |
||||
$setting = 'MySecretSetting'; |
||||
$oldGroups = []; |
||||
$oldGroups[] = AuthorizedGroup::fromParams(['groupId' => 'hello', 'class' => $setting]); |
||||
$goodbye = AuthorizedGroup::fromParams(['groupId' => 'goodbye', 'class' => $setting, 'id' => 42]); |
||||
$oldGroups[] = $goodbye; |
||||
$this->service->expects($this->once()) |
||||
->method('findExistingGroupsForClass') |
||||
->with('MySecretSetting') |
||||
->will($this->returnValue($oldGroups)); |
||||
|
||||
$this->service->expects($this->once()) |
||||
->method('delete') |
||||
->with(42); |
||||
|
||||
$this->service->expects($this->once()) |
||||
->method('create') |
||||
->with('world', 'MySecretSetting') |
||||
->will($this->returnValue(AuthorizedGroup::fromParams(['groupId' => 'world', 'class' => $setting]))); |
||||
|
||||
$result = $this->controller->saveSettings([['gid' => 'hello'], ['gid' => 'world']], 'MySecretSetting'); |
||||
|
||||
$this->assertEquals(['valid' => true], $result->getData()); |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021 Nextcloud GmbH |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Core\Migrations; |
||||
|
||||
use Closure; |
||||
use OCP\DB\ISchemaWrapper; |
||||
use OCP\Migration\SimpleMigrationStep; |
||||
use OCP\Migration\IOutput; |
||||
|
||||
class Version23000Date20210721100600 extends SimpleMigrationStep { |
||||
|
||||
/** |
||||
* @param IOutput $output |
||||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` |
||||
* @param array $options |
||||
* @return null|ISchemaWrapper |
||||
*/ |
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { |
||||
/** @var ISchemaWrapper $schema */ |
||||
$schema = $schemaClosure(); |
||||
|
||||
$table = $schema->createTable('authorized_groups'); |
||||
$table->addColumn('id', 'integer', [ |
||||
'autoincrement' => true, |
||||
'notnull' => true, |
||||
]); |
||||
$table->addColumn('group_id', 'string', [ |
||||
'notnull' => true, |
||||
'length' => 200 |
||||
]); |
||||
$table->addColumn('class', 'string', [ |
||||
'notnull' => true, |
||||
'length' => 200, |
||||
]); |
||||
|
||||
$table->setPrimaryKey(['id']); |
||||
$table->addIndex(['group_id'], 'admindel_groupid_idx'); |
||||
return $schema; |
||||
} |
||||
} |
@ -0,0 +1,50 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Settings; |
||||
|
||||
use OCP\AppFramework\Db\Entity; |
||||
|
||||
/** |
||||
* @method setGroupId(string $groupId) |
||||
* @method setClass(string $class) |
||||
* @method getGroupId(): string |
||||
* @method getClass(): string |
||||
*/ |
||||
class AuthorizedGroup extends Entity implements \JsonSerializable { |
||||
|
||||
/** @var string $group_id */ |
||||
protected $groupId; |
||||
|
||||
/** @var string $class */ |
||||
protected $class; |
||||
|
||||
public function jsonSerialize(): array { |
||||
return [ |
||||
'id' => $this->id, |
||||
'group_id' => $this->groupId, |
||||
'class' => $this->class |
||||
]; |
||||
} |
||||
} |
@ -0,0 +1,125 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <https://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Settings; |
||||
|
||||
use OCP\AppFramework\Db\Entity; |
||||
use OCP\AppFramework\Db\QBMapper; |
||||
use OCP\DB\Exception; |
||||
use OCP\DB\QueryBuilder\IQueryBuilder; |
||||
use OCP\IDBConnection; |
||||
use OCP\IGroup; |
||||
use OCP\IGroupManager; |
||||
use OCP\IUser; |
||||
|
||||
class AuthorizedGroupMapper extends QBMapper { |
||||
public function __construct(IDBConnection $db) { |
||||
parent::__construct($db, 'authorized_groups', AuthorizedGroup::class); |
||||
} |
||||
|
||||
/** |
||||
* @throws Exception |
||||
*/ |
||||
public function findAllClassesForUser(IUser $user): array { |
||||
$qb = $this->db->getQueryBuilder(); |
||||
|
||||
/** @var IGroupManager $groupManager */ |
||||
$groupManager = \OC::$server->get(IGroupManager::class); |
||||
$groups = $groupManager->getUserGroups($user); |
||||
if (count($groups) === 0) { |
||||
return []; |
||||
} |
||||
|
||||
$result = $qb->select('class') |
||||
->from($this->getTableName(), 'auth') |
||||
->where($qb->expr()->in('group_id', array_map(function (IGroup $group) use ($qb) { |
||||
return $qb->createNamedParameter($group->getGID()); |
||||
}, $groups), IQueryBuilder::PARAM_STR)) |
||||
->executeQuery(); |
||||
|
||||
$classes = []; |
||||
while ($row = $result->fetch()) { |
||||
$classes[] = $row['class']; |
||||
} |
||||
$result->closeCursor(); |
||||
return $classes; |
||||
} |
||||
|
||||
/** |
||||
* @throws \OCP\AppFramework\Db\DoesNotExistException |
||||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException |
||||
* @throws \OCP\DB\Exception |
||||
*/ |
||||
public function find(int $id): AuthorizedGroup { |
||||
$queryBuilder = $this->db->getQueryBuilder(); |
||||
$queryBuilder->select('*') |
||||
->from($this->getTableName()) |
||||
->where($queryBuilder->expr()->eq('id', $queryBuilder->createNamedParameter($id))); |
||||
/** @var AuthorizedGroup $authorizedGroup */ |
||||
$authorizedGroup = $this->findEntity($queryBuilder); |
||||
return $authorizedGroup; |
||||
} |
||||
|
||||
/** |
||||
* Get all the authorizations stored in the database. |
||||
* |
||||
* @return AuthorizedGroup[] |
||||
* @throws \OCP\DB\Exception |
||||
*/ |
||||
public function findAll(): array { |
||||
$qb = $this->db->getQueryBuilder(); |
||||
$qb->select('*')->from($this->getTableName()); |
||||
return $this->findEntities($qb); |
||||
} |
||||
|
||||
public function findByGroupIdAndClass(string $groupId, string $class) { |
||||
$qb = $this->db->getQueryBuilder(); |
||||
$qb->select('*') |
||||
->from($this->getTableName()) |
||||
->where($qb->expr()->eq('group_id', $qb->createNamedParameter($groupId))) |
||||
->andWhere($qb->expr()->eq('class', $qb->createNamedParameter($class))); |
||||
return $this->findEntity($qb); |
||||
} |
||||
|
||||
/** |
||||
* @return Entity[] |
||||
* @throws \OCP\DB\Exception |
||||
*/ |
||||
public function findExistingGroupsForClass(string $class): array { |
||||
$qb = $this->db->getQueryBuilder(); |
||||
$qb->select('*') |
||||
->from($this->getTableName()) |
||||
->where($qb->expr()->eq('class', $qb->createNamedParameter($class))); |
||||
return $this->findEntities($qb); |
||||
} |
||||
|
||||
/** |
||||
* @throws Exception |
||||
*/ |
||||
public function removeGroup(string $gid) { |
||||
$qb = $this->db->getQueryBuilder(); |
||||
$qb->delete($this->getTableName()) |
||||
->where($qb->expr()->eq('group_id', $qb->createNamedParameter($gid))) |
||||
->executeStatement(); |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) Nextcloud GmbH |
||||
* |
||||
* @author Carl Schwan <carl@carlschwan.eu> |
||||
* |
||||
* @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 <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
namespace OCP\Settings; |
||||
|
||||
/** |
||||
* Special cases of settings that can be allowed to use by member of special |
||||
* groups. |
||||
* @since 23.0.0 |
||||
*/ |
||||
interface IDelegatedSettings extends ISettings { |
||||
/** |
||||
* Get the name of the settings to differentiate settings inside a section or |
||||
* null if only the section name should be displayed. |
||||
* @since 23.0.0 |
||||
*/ |
||||
public function getName(): ?string; |
||||
|
||||
/** |
||||
* Get a list of authorized app config that this setting is allowed to modify. |
||||
* The format of the array is the following: |
||||
* ```php |
||||
* <?php |
||||
* [ |
||||
* 'app_name' => [ |
||||
* '/simple_key/', # value |
||||
* '/s[a-z]*ldap/', # regex |
||||
* ], |
||||
* 'another_app_name => [ ... ], |
||||
* ] |
||||
* ``` |
||||
* @since 23.0.0 |
||||
*/ |
||||
public function getAuthorizedAppConfig(): array; |
||||
} |
Loading…
Reference in new issue