Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/superuser change role #956

Open
wants to merge 15 commits into
base: 9.next
Choose a base branch
from
5 changes: 4 additions & 1 deletion Docs/Documentation/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ NOTE: SOME keys were hidden in this doc page, please refer to `vendor/cakedc/use
// configure Remember Me component
'active' => true,
],
'Superuser' => ['allowedToChangePasswords' => false], // able to reset any users password
'Superuser' => [
'allowedToChangePasswords' => false,// able to reset any users password
'allowedToChangeRoles' => false // able to change user roles
],
],
//Default authentication/authorization setup
'Auth' => [
Expand Down
9 changes: 8 additions & 1 deletion config/users.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,14 @@
]
]
],
'Superuser' => ['allowedToChangePasswords' => false], // able to reset any users password
'Superuser' => [
'allowedToChangePasswords' => false,// able to reset any users password
'allowedToChangeRoles' => false // able to change user roles
],
'AvailableRoles'=>[
'admin',
'user'
],
],
'OneTimePasswordAuthenticator' => [
'checker' => \CakeDC\Auth\Authentication\DefaultOneTimePasswordAuthenticationChecker::class,
Expand Down
142 changes: 142 additions & 0 deletions src/Controller/Traits/RoleManagementTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php
declare(strict_types=1);

/**
* Copyright 2010 - 2019, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2010 - 2018, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/

namespace CakeDC\Users\Controller\Traits;

use Cake\Core\Configure;
use CakeDC\Users\Exception\ConfigNotSetException;
use CakeDC\Users\Exception\UserNotFoundException;
use CakeDC\Users\Model\Table\UsersTable;
use CakeDC\Users\Plugin;
use Exception;
use phpDocumentor\Reflection\Types\Integer;

/**
* Covers the password management: reset, change
*
* @property \Cake\Http\ServerRequest $request
*/
trait RoleManagementTrait
{

/**
* Change Role
* Can be used by superadmin to change user roles
*
* @param int|string|null $id user_id, null for logged in user id
* @return mixed
*/
public function changeRole($id = null)
{

$identity = $this->getRequest()->getAttribute('identity');
$identity = $identity ?? [];
$userId = $identity['id'] ?? null;

if ($userId) {
if ($this->canUserEditRole($id, $identity)) {
// superuser update user roles
$user = $this->getUsersTable()->get($id);
$configRoles = $this->getConfigRoles();
if (!$configRoles) {
//set the defaults
$configRoles = [UsersTable::ROLE_ADMIN, UsersTable::ROLE_USER];
}
$availableRoles = [];
peter2796b marked this conversation as resolved.
Show resolved Hide resolved
foreach ($configRoles as $role) {
$availableRoles[$role] = $role;
}
$redirect = ['action' => 'index'];
} else {
$this->Flash->error(
__d('cake_d_c/users', 'Changing role is not allowed')
);

return $this->redirect(Configure::read('Users.Profile.route'));
}
} else {
$this->Flash->error(
__d('cake_d_c/users', 'Login to perform this action')
);
return $this->redirect(Configure::read('Users.Profile.route'));
}

if ($this->getRequest()->is(['post', 'put'])) {
try {
if (!in_array($this->getRequest()->getData()['role'], $availableRoles)) {
throw new Exception('Invalid role supplied');
}
$user = $this->getUsersTable()->patchEntity(
$user,
$this->getRequest()->getData(),
[
'accessibleFields' => [
'role' => true,
'is_superuser' => true,
],
]
);


if ($user->getErrors()) {
$this->Flash->error(__d('cake_d_c/users', 'Role could not be changed'));
} else {
$result = $this->getUsersTable()->save($user);
if ($result) {
$event = $this->dispatchEvent(Plugin::EVENT_AFTER_CHANGE_ROLE, ['user' => $result]);
if (!empty($event) && is_array($event->getResult())) {
return $this->redirect($event->getResult());
}
$this->Flash->success(__d('cake_d_c/users', 'Role has been changed successfully'));

return $this->redirect($redirect);
} else {
$this->Flash->error(__d('cake_d_c/users', 'Role could not be changed'));
}
}
} catch (UserNotFoundException $exception) {
$this->Flash->error(__d('cake_d_c/users', 'User was not found'));
} catch (Exception $exception) {
$this->Flash->error(__d('cake_d_c/users', 'Role could not be changed'));
$this->log($exception->getMessage());
}
}
$this->set(compact('user', 'availableRoles'));
$this->set('_serialize', ['user']);
}

/**
* Checks and returns boolean value if the user can edit the role
* @param int|string|null $id user_id, null for logged in user id
* @param mixed|string $identity
* @return bool
*/
protected function canUserEditRole($id, $identity)
{
return $id && $identity['is_superuser'] && Configure::read('Users.Superuser.allowedToChangeRoles');
}


/**
* @return array|false[]|mixed
*/
protected function getConfigRoles()
{
$configRoles = Configure::read('Users.AvailableRoles');
if (is_array($configRoles) && count($configRoles) == 0) {
//if the config key is present and roles array is empty
throw new ConfigNotSetException('No Available role found in the users config. please set Users.AvailableRoles');
}
return $configRoles;
}
}
2 changes: 2 additions & 0 deletions src/Controller/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use CakeDC\Users\Controller\Traits\ProfileTrait;
use CakeDC\Users\Controller\Traits\ReCaptchaTrait;
use CakeDC\Users\Controller\Traits\RegisterTrait;
use CakeDC\Users\Controller\Traits\RoleManagementTrait;
use CakeDC\Users\Controller\Traits\SimpleCrudTrait;
use CakeDC\Users\Controller\Traits\SocialTrait;
use CakeDC\Users\Controller\Traits\U2fTrait;
Expand All @@ -37,6 +38,7 @@ class UsersController extends AppController
use ProfileTrait;
use ReCaptchaTrait;
use RegisterTrait;
use RoleManagementTrait;
use SimpleCrudTrait;
use SocialTrait;
use U2fTrait;
Expand Down
19 changes: 19 additions & 0 deletions src/Exception/ConfigNotSetException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);

/**
* Copyright 2010 - 2019, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2010 - 2018, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/

namespace CakeDC\Users\Exception;


class ConfigNotSetException extends \Exception
{
}
1 change: 1 addition & 0 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Plugin extends BasePlugin implements AuthenticationServiceProviderInterfac
public const EVENT_BEFORE_REGISTER = 'Users.Global.beforeRegister';
public const EVENT_AFTER_REGISTER = 'Users.Global.afterRegister';
public const EVENT_AFTER_CHANGE_PASSWORD = 'Users.Global.afterResetPassword';
public const EVENT_AFTER_CHANGE_ROLE = 'Users.Global.afterRoleChanged';
public const EVENT_BEFORE_SOCIAL_LOGIN_USER_CREATE = 'Users.Global.beforeSocialLoginUserCreate';
public const EVENT_BEFORE_SOCIAL_LOGIN_REDIRECT = 'Users.Global.beforeSocialLoginRedirect';
public const EVENT_SOCIAL_LOGIN_EXISTING_ACCOUNT = 'Users.Global.socialLoginExistingAccount';
Expand Down
13 changes: 13 additions & 0 deletions templates/Users/change_role.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create($user) ?>
<fieldset>
<legend><?= __d('cake_d_c/users', 'Select a new role') ?></legend>

<?= $this->Form->select('role', $availableRoles, ['empty' => false]); ?>
<?= $this->Form->control('is_superuser', ['type' => 'checkbox','label'=>'Superuser']);?>

</fieldset>
<?= $this->Form->button(__d('cake_d_c/users', 'Submit')); ?>
<?= $this->Form->end() ?>
</div>
1 change: 1 addition & 0 deletions templates/Users/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<td class="actions">
<?= $this->Html->link(__d('cake_d_c/users', 'View'), ['action' => 'view', $user->id]) ?>
<?= $this->Html->link(__d('cake_d_c/users', 'Change password'), ['action' => 'changePassword', $user->id]) ?>
<?= $this->Html->link(__d('cake_d_c/users', 'Change role'), ['action' => 'changeRole', $user->id]) ?>
<?= $this->Html->link(__d('cake_d_c/users', 'Edit'), ['action' => 'edit', $user->id]) ?>
<?= $this->Form->postLink(__d('cake_d_c/users', 'Delete'), ['action' => 'delete', $user->id], ['confirm' => __d('cake_d_c/users', 'Are you sure you want to delete # {0}?', $user->id)]) ?>
</td>
Expand Down
Loading