Merge branch 'develop'
commit
7678fe1b9b
|
@ -7,6 +7,7 @@ use Cake\Http\Exception\UnauthorizedException;
|
||||||
use Cake\Http\Exception\MethodNotAllowedException;
|
use Cake\Http\Exception\MethodNotAllowedException;
|
||||||
use Cake\Core\Configure;
|
use Cake\Core\Configure;
|
||||||
use Cake\Utility\Security;
|
use Cake\Utility\Security;
|
||||||
|
use Cake\Http\Exception\NotFoundException;
|
||||||
|
|
||||||
class UsersController extends AppController
|
class UsersController extends AppController
|
||||||
{
|
{
|
||||||
|
@ -93,7 +94,7 @@ class UsersController extends AppController
|
||||||
throw new MethodNotAllowedException(__('No valid organisation found. Either encode the organisation separately or select a valid one.'));
|
throw new MethodNotAllowedException(__('No valid organisation found. Either encode the organisation separately or select a valid one.'));
|
||||||
}
|
}
|
||||||
$data['individual']['alignments'][] = ['type' => 'Member', 'organisation' => ['uuid' => $existingOrg['uuid']]];
|
$data['individual']['alignments'][] = ['type' => 'Member', 'organisation' => ['uuid' => $existingOrg['uuid']]];
|
||||||
$data['individual_id'] = $this->Users->Individuals->captureIndividual($data['individual']);
|
$data['individual_id'] = $this->Users->Individuals->captureIndividual($data['individual'], true);
|
||||||
} else if (!$currentUser['role']['perm_admin'] && isset($data['individual_id'])) {
|
} else if (!$currentUser['role']['perm_admin'] && isset($data['individual_id'])) {
|
||||||
if (!in_array($data['individual_id'], $individual_ids)) {
|
if (!in_array($data['individual_id'], $individual_ids)) {
|
||||||
throw new MethodNotAllowedException(__('The selected individual is not aligned with your organisation. Creating a user for them is not permitted.'));
|
throw new MethodNotAllowedException(__('The selected individual is not aligned with your organisation. Creating a user for them is not permitted.'));
|
||||||
|
@ -157,7 +158,10 @@ class UsersController extends AppController
|
||||||
}
|
}
|
||||||
$this->CRUD->view($id, [
|
$this->CRUD->view($id, [
|
||||||
'contain' => ['Individuals' => ['Alignments' => 'Organisations'], 'Roles', 'Organisations'],
|
'contain' => ['Individuals' => ['Alignments' => 'Organisations'], 'Roles', 'Organisations'],
|
||||||
'afterFind' => function($data) use ($keycloakUsersParsed) {
|
'afterFind' => function($data) use ($keycloakUsersParsed, $currentUser) {
|
||||||
|
if (empty($currentUser['role']['perm_admin']) && $currentUser['organisation_id'] != $data['organisation_id']) {
|
||||||
|
throw new NotFoundException(__('Invalid User.'));
|
||||||
|
}
|
||||||
$data = $this->fetchTable('PermissionLimitations')->attachLimitations($data);
|
$data = $this->fetchTable('PermissionLimitations')->attachLimitations($data);
|
||||||
if (!empty(Configure::read('keycloak.enabled'))) {
|
if (!empty(Configure::read('keycloak.enabled'))) {
|
||||||
$keycloakUser = $keycloakUsersParsed[$data->username] ?? [];
|
$keycloakUser = $keycloakUsersParsed[$data->username] ?? [];
|
||||||
|
@ -184,11 +188,6 @@ class UsersController extends AppController
|
||||||
$individual_ids = [];
|
$individual_ids = [];
|
||||||
if (!$currentUser['role']['perm_admin']) {
|
if (!$currentUser['role']['perm_admin']) {
|
||||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_admin' => 0, 'perm_org_admin' => 0])->all()->toArray();
|
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_admin' => 0, 'perm_org_admin' => 0])->all()->toArray();
|
||||||
$individual_ids = $this->Users->Individuals->find('aligned', ['organisation_id' => $currentUser['organisation_id']])->all()->extract('id')->toArray();
|
|
||||||
if (empty($individual_ids)) {
|
|
||||||
$individual_ids = [-1];
|
|
||||||
}
|
|
||||||
$individuals_params['conditions'] = ['id IN' => $individual_ids];
|
|
||||||
} else {
|
} else {
|
||||||
$validRoles = $this->Users->Roles->find('list')->order(['name' => 'asc'])->all()->toArray();
|
$validRoles = $this->Users->Roles->find('list')->order(['name' => 'asc'])->all()->toArray();
|
||||||
}
|
}
|
||||||
|
@ -208,7 +207,7 @@ class UsersController extends AppController
|
||||||
'contain' => ['Roles', ],
|
'contain' => ['Roles', ],
|
||||||
];
|
];
|
||||||
if ($this->request->is(['get'])) {
|
if ($this->request->is(['get'])) {
|
||||||
$params['fields'] = array_merge($params['fields'], ['individual_id', 'role_id', 'disabled']);
|
$params['fields'] = array_merge($params['fields'], ['role_id', 'disabled']);
|
||||||
if (!empty($this->ACL->getUser()['role']['perm_admin'])) {
|
if (!empty($this->ACL->getUser()['role']['perm_admin'])) {
|
||||||
$params['fields'][] = 'organisation_id';
|
$params['fields'][] = 'organisation_id';
|
||||||
}
|
}
|
||||||
|
@ -224,7 +223,6 @@ class UsersController extends AppController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->request->is(['post', 'put']) && !empty($this->ACL->getUser()['role']['perm_admin'])) {
|
if ($this->request->is(['post', 'put']) && !empty($this->ACL->getUser()['role']['perm_admin'])) {
|
||||||
$params['fields'][] = 'individual_id';
|
|
||||||
$params['fields'][] = 'role_id';
|
$params['fields'][] = 'role_id';
|
||||||
$params['fields'][] = 'organisation_id';
|
$params['fields'][] = 'organisation_id';
|
||||||
$params['fields'][] = 'disabled';
|
$params['fields'][] = 'disabled';
|
||||||
|
@ -254,22 +252,12 @@ class UsersController extends AppController
|
||||||
if (!empty($responsePayload)) {
|
if (!empty($responsePayload)) {
|
||||||
return $responsePayload;
|
return $responsePayload;
|
||||||
}
|
}
|
||||||
$dropdownData = [
|
|
||||||
'role' => $validRoles,
|
|
||||||
'individual' => $this->Users->Individuals->find('list', [
|
|
||||||
'sort' => ['email' => 'asc']
|
|
||||||
]),
|
|
||||||
'organisation' => $this->Users->Organisations->find('list', [
|
|
||||||
'sort' => ['name' => 'asc']
|
|
||||||
])
|
|
||||||
];
|
|
||||||
$org_conditions = [];
|
$org_conditions = [];
|
||||||
if (empty($currentUser['role']['perm_admin'])) {
|
if (empty($currentUser['role']['perm_admin'])) {
|
||||||
$org_conditions = ['id' => $currentUser['organisation_id']];
|
$org_conditions = ['id' => $currentUser['organisation_id']];
|
||||||
}
|
}
|
||||||
$dropdownData = [
|
$dropdownData = [
|
||||||
'role' => $validRoles,
|
'role' => $validRoles,
|
||||||
'individual' => $this->Users->Individuals->find('list', $individuals_params)->toArray(),
|
|
||||||
'organisation' => $this->Users->Organisations->find('list', [
|
'organisation' => $this->Users->Organisations->find('list', [
|
||||||
'sort' => ['name' => 'asc'],
|
'sort' => ['name' => 'asc'],
|
||||||
'conditions' => $org_conditions
|
'conditions' => $org_conditions
|
||||||
|
@ -396,6 +384,7 @@ class UsersController extends AppController
|
||||||
if (Configure::read('keycloak.enabled')) {
|
if (Configure::read('keycloak.enabled')) {
|
||||||
$this->redirect($this->Users->keyCloaklogout());
|
$this->redirect($this->Users->keyCloaklogout());
|
||||||
}
|
}
|
||||||
|
$this->request->getSession()->destroy();
|
||||||
return $this->redirect(\Cake\Routing\Router::url('/users/login'));
|
return $this->redirect(\Cake\Routing\Router::url('/users/login'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -455,7 +455,17 @@ class AuthKeycloakBehavior extends Behavior
|
||||||
$user['meta_fields'] = $temp;
|
$user['meta_fields'] = $temp;
|
||||||
$differences = [];
|
$differences = [];
|
||||||
$keycloakUser = $keycloakUsersParsed[$username] ?? [];
|
$keycloakUser = $keycloakUsersParsed[$username] ?? [];
|
||||||
$requireUpdate = $this->checkKeycloakUserRequiresUpdate($keycloakUser, $user, $differences);
|
if (empty($keycloakUser)) {
|
||||||
|
$requireUpdate = true;
|
||||||
|
$differences = [
|
||||||
|
'user' => [
|
||||||
|
'keycloak' => 'USER NOT FOUND',
|
||||||
|
'cerebrate' => $user['username']
|
||||||
|
]
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$requireUpdate = $this->checkKeycloakUserRequiresUpdate($keycloakUser, $user, $differences);
|
||||||
|
}
|
||||||
$status[$user['id']] = [
|
$status[$user['id']] = [
|
||||||
'require_update' => $requireUpdate,
|
'require_update' => $requireUpdate,
|
||||||
'differences' => $differences,
|
'differences' => $differences,
|
||||||
|
|
|
@ -6,6 +6,8 @@ use App\Model\Table\AppTable;
|
||||||
use Cake\ORM\Table;
|
use Cake\ORM\Table;
|
||||||
use Cake\Validation\Validator;
|
use Cake\Validation\Validator;
|
||||||
use Cake\ORM\Query;
|
use Cake\ORM\Query;
|
||||||
|
use Cake\ORM\RulesChecker;
|
||||||
|
use Cake\Core\Configure;
|
||||||
|
|
||||||
|
|
||||||
class IndividualsTable extends AppTable
|
class IndividualsTable extends AppTable
|
||||||
|
@ -46,6 +48,12 @@ class IndividualsTable extends AppTable
|
||||||
$this->setDisplayField('email');
|
$this->setDisplayField('email');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildRules(RulesChecker $rules): RulesChecker
|
||||||
|
{
|
||||||
|
$rules->add($rules->isUnique(['email']));
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
public function validationDefault(Validator $validator): Validator
|
public function validationDefault(Validator $validator): Validator
|
||||||
{
|
{
|
||||||
$validator
|
$validator
|
||||||
|
@ -54,7 +62,7 @@ class IndividualsTable extends AppTable
|
||||||
return $validator;
|
return $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function captureIndividual($individual): ?int
|
public function captureIndividual($individual, $skipUpdate = false): ?int
|
||||||
{
|
{
|
||||||
if (!empty($individual['uuid'])) {
|
if (!empty($individual['uuid'])) {
|
||||||
$existingIndividual = $this->find()->where([
|
$existingIndividual = $this->find()->where([
|
||||||
|
@ -71,6 +79,9 @@ class IndividualsTable extends AppTable
|
||||||
'accessibleFields' => $entityToSave->getAccessibleFieldForNew()
|
'accessibleFields' => $entityToSave->getAccessibleFieldForNew()
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
|
if ($skipUpdate) {
|
||||||
|
return $existingIndividual->id;
|
||||||
|
}
|
||||||
$this->patchEntity($existingIndividual, $individual);
|
$this->patchEntity($existingIndividual, $individual);
|
||||||
$entityToSave = $existingIndividual;
|
$entityToSave = $existingIndividual;
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,6 +328,24 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
'Users' => [
|
||||||
|
'Users' => [
|
||||||
|
'Settings' => [
|
||||||
|
'user.multiple-users-per-individual' => [
|
||||||
|
'name' => __('Multiple users per individual'),
|
||||||
|
'type' => 'boolean',
|
||||||
|
'description' => __('Allow for multiple user accounts to be assigned to a single user account. This setting will automatically be restricted when using KeyCloak.'),
|
||||||
|
'default' => false
|
||||||
|
],
|
||||||
|
'user.username-must-be-email' => [
|
||||||
|
'name' => __('Usernames must be e-mail addresses'),
|
||||||
|
'type' => 'boolean',
|
||||||
|
'description' => __('This setting will enforce that usernames conform to basic requirements of e-mail addresses.'),
|
||||||
|
'default' => false
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
/*
|
/*
|
||||||
'Features' => [
|
'Features' => [
|
||||||
'Demo Settings' => [
|
'Demo Settings' => [
|
||||||
|
|
|
@ -175,11 +175,22 @@ class UsersTable extends AppTable
|
||||||
])
|
])
|
||||||
->requirePresence(['username'], 'create')
|
->requirePresence(['username'], 'create')
|
||||||
->notEmptyString('username', __('Please fill this field'), 'create');
|
->notEmptyString('username', __('Please fill this field'), 'create');
|
||||||
|
if (Configure::read('user.username-must-be-email')) {
|
||||||
|
$validator->add('username', 'valid_email', [
|
||||||
|
'rule' => 'email',
|
||||||
|
'message' => 'Username has to be a valid e-mail address.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
return $validator;
|
return $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildRules(RulesChecker $rules): RulesChecker
|
public function buildRules(RulesChecker $rules): RulesChecker
|
||||||
{
|
{
|
||||||
|
$rules->add($rules->isUnique(['username']));
|
||||||
|
$allowDuplicateIndividuals = false;
|
||||||
|
if (empty(Configure::read('user.multiple-users-per-individual')) || !empty(Configure::read('keycloak.enabled'))) {
|
||||||
|
$rules->add($rules->isUnique(['individual_id']));
|
||||||
|
}
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"version": "1.9",
|
"version": "1.10",
|
||||||
"application": "Cerebrate"
|
"application": "Cerebrate"
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
'field' => 'individual_id',
|
'field' => 'individual_id',
|
||||||
'type' => 'dropdown',
|
'type' => 'dropdown',
|
||||||
'label' => __('Associated individual'),
|
'label' => __('Associated individual'),
|
||||||
'options' => $dropdownData['individual']
|
'options' => isset($dropdownData['individual']) ? $dropdownData['individual'] : [],
|
||||||
|
'conditions' => $this->request->getParam('action') === 'add'
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'field' => 'individual.email',
|
'field' => 'individual.email',
|
||||||
|
|
Loading…
Reference in New Issue