Compare commits
44 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
04322b24df | |
![]() |
4f1835dc4c | |
![]() |
50b65021dc | |
![]() |
55695fc09b | |
![]() |
0c320f7d9c | |
![]() |
ffd6c50294 | |
![]() |
9c54a4842f | |
![]() |
1572681307 | |
![]() |
0ed3bef000 | |
![]() |
cfceaf0fb7 | |
![]() |
04b640c8b6 | |
![]() |
cce4115418 | |
![]() |
d799214a41 | |
![]() |
1c8bcc045e | |
![]() |
da4bd943b7 | |
![]() |
467ec29f54 | |
![]() |
07f67fe9ea | |
![]() |
8e87dd8b28 | |
![]() |
39e9fb4a76 | |
![]() |
0131422ab8 | |
![]() |
be290b6f10 | |
![]() |
041028e04c | |
![]() |
ed592c57c7 | |
![]() |
8d953cd848 | |
![]() |
6fcf5d0b02 | |
![]() |
f7f9392cfe | |
![]() |
b8ff31a906 | |
![]() |
1702b84fe8 | |
![]() |
a1020bc42b | |
![]() |
850d559cef | |
![]() |
55cac2e2e6 | |
![]() |
ab331dcfb9 | |
![]() |
ac33e90f0c | |
![]() |
b45cc8ae22 | |
![]() |
54e4fca637 | |
![]() |
6813013379 | |
![]() |
9b92f86627 | |
![]() |
a63bb216dd | |
![]() |
7d08623ca8 | |
![]() |
9e69bc7239 | |
![]() |
e8f5165b11 | |
![]() |
5d0b7715db | |
![]() |
2eb6b1ae77 | |
![]() |
a05f28147f |
|
@ -22,20 +22,29 @@ class AuthKeysController extends AppController
|
|||
{
|
||||
$currentUser = $this->ACL->getUser();
|
||||
$conditions = [];
|
||||
$userId = $this->request->getQuery('Users_id');
|
||||
if (!empty($userId)) {
|
||||
$conditions['AND']['Users.id'] = $userId;
|
||||
}
|
||||
|
||||
if (empty($currentUser['role']['perm_community_admin'])) {
|
||||
$conditions['Users.organisation_id'] = $currentUser['organisation_id'];
|
||||
if (empty($currentUser['role']['perm_org_admin'])) {
|
||||
$conditions['Users.id'] = $currentUser['id'];
|
||||
}
|
||||
}
|
||||
$this->CRUD->index([
|
||||
$indexOptions = [
|
||||
'filters' => $this->filterFields,
|
||||
'quickFilters' => $this->quickFilterFields,
|
||||
'contain' => $this->containFields,
|
||||
'exclude_fields' => ['authkey'],
|
||||
'conditions' => $conditions,
|
||||
'hidden' => []
|
||||
]);
|
||||
];
|
||||
if (!empty($userId)) {
|
||||
$indexOptions['action_query_strings'] = ['Users.id' => $userId];
|
||||
}
|
||||
$this->CRUD->index($indexOptions);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
|
@ -46,13 +55,7 @@ class AuthKeysController extends AppController
|
|||
public function delete($id)
|
||||
{
|
||||
$currentUser = $this->ACL->getUser();
|
||||
$conditions = [];
|
||||
if (empty($currentUser['role']['perm_community_admin'])) {
|
||||
$conditions['Users.organisation_id'] = $currentUser['organisation_id'];
|
||||
if (empty($currentUser['role']['perm_org_admin'])) {
|
||||
$conditions['Users.id'] = $currentUser['id'];
|
||||
}
|
||||
}
|
||||
$conditions = $this->AuthKeys->buildUserConditions($currentUser);
|
||||
$this->CRUD->delete($id, ['conditions' => $conditions, 'contain' => 'Users']);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
|
@ -67,21 +70,14 @@ class AuthKeysController extends AppController
|
|||
$validUsers = [];
|
||||
$userConditions = [];
|
||||
$currentUser = $this->ACL->getUser();
|
||||
if (empty($currentUser['role']['perm_community_admin'])) {
|
||||
if (empty($currentUser['role']['perm_org_admin'])) {
|
||||
$userConditions['id'] = $currentUser['id'];
|
||||
} else {
|
||||
$role_ids = $this->Users->Roles->find()->where(['perm_admin' => 0, 'perm_community_admin', 'perm_org_admin' => 0])->all()->extract('id')->toList();
|
||||
$userConditions['organisation_id'] = $currentUser['organisation_id'];
|
||||
$userConditions['OR'] = [
|
||||
['role_id IN' => $role_ids],
|
||||
['id' => $currentUser['id']],
|
||||
];
|
||||
}
|
||||
}
|
||||
$conditions = $this->AuthKeys->buildUserConditions($currentUser);
|
||||
$userId = $this->request->getQuery('Users_id');
|
||||
$users = $this->Users->find('list');
|
||||
if (!empty($userConditions)) {
|
||||
$users->where($userConditions);
|
||||
if (!empty($conditions)) {
|
||||
$users->where($conditions);
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
$users->where(['Users.id' => $userId]);
|
||||
}
|
||||
$users = $users->order(['username' => 'asc'])->all()->toArray();
|
||||
$this->CRUD->add([
|
||||
|
|
|
@ -363,11 +363,19 @@ class ACLComponent extends Component
|
|||
return true;
|
||||
}
|
||||
|
||||
if ($user['role']['perm_community_admin']) {
|
||||
return false; // org_admins cannot edit admins
|
||||
$this->Roles = TableRegistry::get('Roles');
|
||||
$validRoles = [];
|
||||
if (!$currentUser['role']['perm_community_admin']) {
|
||||
if ($currentUser['role']['perm_group_admin']) {
|
||||
$validRoles = $this->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_admin' => 0])->all()->toArray();
|
||||
} else {
|
||||
$validRoles = $this->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_org_admin' => 0, 'perm_admin' => 0])->all()->toArray();
|
||||
}
|
||||
} else {
|
||||
$validRoles = $this->Roles->find('list')->order(['name' => 'asc'])->all()->toArray();
|
||||
}
|
||||
if ($currentUser['role']['perm_org_admin'] && $user['role']['perm_group_admin']) {
|
||||
return false; // org_admins cannot edit group_admin
|
||||
if (!in_array($user['role_id'], array_keys($validRoles)) && $currentUser['id'] != $user['id']) {
|
||||
return false;
|
||||
}
|
||||
if ($currentUser['role']['perm_group_admin']) {
|
||||
$this->OrgGroups = TableRegistry::get('OrgGroups');
|
||||
|
@ -378,9 +386,6 @@ class ACLComponent extends Component
|
|||
if (!$currentUser['role']['perm_org_admin']) {
|
||||
return false;
|
||||
} else {
|
||||
if ($currentUser['id'] == $user['id']) {
|
||||
return true;
|
||||
}
|
||||
if ($currentUser['organisation_id'] === $user['organisation_id']) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -272,6 +272,10 @@ class CRUDComponent extends Component
|
|||
$this->Controller->set('model', $this->Table);
|
||||
$this->Controller->set('data', $data);
|
||||
$this->Controller->set('embedInModal', $embedInModal);
|
||||
if (!empty($options['action_query_strings'])) {
|
||||
$this->Controller->set('action_query_strings', $options['action_query_strings']);
|
||||
|
||||
}
|
||||
$this->Controller->set('skipTableToolbar', $skipTableToolbar);
|
||||
}
|
||||
}
|
||||
|
@ -465,51 +469,73 @@ class CRUDComponent extends Component
|
|||
}
|
||||
}
|
||||
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
|
||||
$break = false;
|
||||
if (isset($params['beforeSave'])) {
|
||||
$data = $params['beforeSave']($data);
|
||||
try {
|
||||
$data = $params['beforeSave']($data);
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Could not save {0}.', $this->ObjectAlias), $message);
|
||||
}
|
||||
if ($data === false) {
|
||||
throw new NotFoundException(__('Could not save {0} due to the input failing to meet expectations. Your input is bad and you should feel bad.', $this->ObjectAlias));
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Could not save {0} due to the input failing to meet expectations. Your input is bad and you should feel bad.', $this->ObjectAlias));
|
||||
}
|
||||
}
|
||||
$savedData = $this->Table->save($data);
|
||||
if ($savedData !== false) {
|
||||
if (isset($params['afterSave'])) {
|
||||
$params['afterSave']($data);
|
||||
}
|
||||
$message = __('{0} added.', $this->ObjectAlias);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
if (!empty($params['displayOnSuccess'])) {
|
||||
$displayOnSuccess = $this->renderViewInVariable($params['displayOnSuccess'], ['entity' => $data]);
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message, ['displayOnSuccess' => $displayOnSuccess]);
|
||||
} else {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message);
|
||||
if (!$break) {
|
||||
$savedData = $this->Table->save($data);
|
||||
if ($savedData !== false) {
|
||||
if (isset($params['afterSave'])) {
|
||||
try {
|
||||
$data = $params['afterSave']($data);
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Saved {0}, but could not execute post-save actions.', $this->ObjectAlias), $message);
|
||||
}
|
||||
if ($data === false) {
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Saved {0}, but the post-save actons failed.', $this->ObjectAlias));
|
||||
}
|
||||
}
|
||||
if (!$break) {
|
||||
$message = __('{0} added.', $this->ObjectAlias);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
if (!empty($params['displayOnSuccess'])) {
|
||||
$displayOnSuccess = $this->renderViewInVariable($params['displayOnSuccess'], ['entity' => $data]);
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message, ['displayOnSuccess' => $displayOnSuccess]);
|
||||
} else {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'add', $savedData, $message);
|
||||
}
|
||||
} else {
|
||||
$this->Controller->Flash->success($message);
|
||||
if (empty($params['redirect'])) {
|
||||
$this->Controller->redirect(['action' => 'view', $data->id]);
|
||||
} else {
|
||||
$this->Controller->redirect($params['redirect']);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->Controller->Flash->success($message);
|
||||
if (empty($params['redirect'])) {
|
||||
$this->Controller->redirect(['action' => 'view', $data->id]);
|
||||
$this->Controller->isFailResponse = true;
|
||||
$validationErrors = $data->getErrors();
|
||||
$validationMessage = $this->prepareValidationMessage($validationErrors);
|
||||
$message = __(
|
||||
'{0} could not be added.{1}',
|
||||
$this->ObjectAlias,
|
||||
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
|
||||
);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($message, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'add', $data, $message, $validationErrors);
|
||||
} else {
|
||||
$this->Controller->redirect($params['redirect']);
|
||||
$this->Controller->Flash->error($message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->Controller->isFailResponse = true;
|
||||
$validationErrors = $data->getErrors();
|
||||
$validationMessage = $this->prepareValidationMessage($validationErrors);
|
||||
$message = __(
|
||||
'{0} could not be added.{1}',
|
||||
$this->ObjectAlias,
|
||||
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
|
||||
);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($message, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'add', $data, $message, $validationErrors);
|
||||
} else {
|
||||
$this->Controller->Flash->error($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($params['fields'])) {
|
||||
|
@ -723,6 +749,18 @@ class CRUDComponent extends Component
|
|||
return $input;
|
||||
}
|
||||
|
||||
private function __raiseErrorToUser($title, $message = null)
|
||||
{
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($message, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', [], $title, ['Custom checks' => ['Custom checks' => $message]]);
|
||||
} else {
|
||||
$this->Controller->isFailResponse = true;
|
||||
$this->Controller->Flash->error($message);
|
||||
}
|
||||
}
|
||||
|
||||
public function edit(int $id, array $params = []): void
|
||||
{
|
||||
if (empty($id)) {
|
||||
|
@ -800,54 +838,79 @@ class CRUDComponent extends Component
|
|||
}
|
||||
}
|
||||
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
|
||||
$break = false;
|
||||
if (isset($params['beforeSave'])) {
|
||||
$data = $params['beforeSave']($data);
|
||||
try {
|
||||
$data = $params['beforeSave']($data);
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Could not save {0}.', $this->ObjectAlias), $message);
|
||||
}
|
||||
if ($data === false) {
|
||||
throw new NotFoundException(__('Could not save {0} due to the input failing to meet expectations. Your input is bad and you should feel bad.', $this->ObjectAlias));
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Could not save {0} due to the input failing to meet expectations.', $this->ObjectAlias), __('Your input is bad and you should feel bad.'));
|
||||
}
|
||||
}
|
||||
$savedData = $this->Table->save($data);
|
||||
if ($savedData !== false) {
|
||||
if ($metaFieldsEnabled && !empty($metaFieldsToDelete)) {
|
||||
foreach ($metaFieldsToDelete as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($metaFieldsToDelete[$k]);
|
||||
if (!$break) {
|
||||
$savedData = $this->Table->save($data);
|
||||
if ($savedData !== false) {
|
||||
if ($metaFieldsEnabled && !empty($metaFieldsToDelete)) {
|
||||
foreach ($metaFieldsToDelete as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($metaFieldsToDelete[$k]);
|
||||
}
|
||||
}
|
||||
if (!empty($metaFieldsToDelete)) {
|
||||
$this->Table->MetaFields->unlink($savedData, $metaFieldsToDelete);
|
||||
}
|
||||
}
|
||||
if (!empty($metaFieldsToDelete)) {
|
||||
$this->Table->MetaFields->unlink($savedData, $metaFieldsToDelete);
|
||||
$break = false;
|
||||
if (isset($params['afterSave'])) {
|
||||
if (isset($params['afterSave'])) {
|
||||
try {
|
||||
$data = $params['afterSave']($data);
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Saved {0} `{1}`, but could not execute post-save actions.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()}), $message);
|
||||
}
|
||||
if ($data === false) {
|
||||
$break = true;
|
||||
$this->__raiseErrorToUser(__('Saved {0} `{1}`, but the post-save actons failed.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()}));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$break) {
|
||||
$message = __('{0} `{1}` updated.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()});
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'edit', $savedData, $message);
|
||||
} else {
|
||||
$this->Controller->Flash->success($message);
|
||||
if (empty($params['redirect'])) {
|
||||
$this->Controller->redirect(['action' => 'view', $id]);
|
||||
} else {
|
||||
$this->Controller->redirect($params['redirect']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($params['afterSave'])) {
|
||||
$params['afterSave']($data);
|
||||
}
|
||||
$message = __('{0} `{1}` updated.', $this->ObjectAlias, $savedData->{$this->Table->getDisplayField()});
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
$this->Controller->restResponsePayload = $this->RestResponse->viewData($savedData, 'json');
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxSuccessResponse($this->ObjectAlias, 'edit', $savedData, $message);
|
||||
} else {
|
||||
$this->Controller->Flash->success($message);
|
||||
if (empty($params['redirect'])) {
|
||||
$this->Controller->redirect(['action' => 'view', $id]);
|
||||
$validationErrors = $data->getErrors();
|
||||
$validationMessage = $this->prepareValidationError($data);
|
||||
$message = __(
|
||||
'{0} could not be modified.{1}',
|
||||
$this->ObjectAlias,
|
||||
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
|
||||
);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', $data, $message, $validationErrors);
|
||||
} else {
|
||||
$this->Controller->redirect($params['redirect']);
|
||||
$this->Controller->Flash->error($message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$validationErrors = $data->getErrors();
|
||||
$validationMessage = $this->prepareValidationError($data);
|
||||
$message = __(
|
||||
'{0} could not be modified.{1}',
|
||||
$this->ObjectAlias,
|
||||
empty($validationMessage) ? '' : PHP_EOL . __('Reason: {0}', $validationMessage)
|
||||
);
|
||||
if ($this->Controller->ParamHandler->isRest()) {
|
||||
} else if ($this->Controller->ParamHandler->isAjax()) {
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', $data, $message, $validationErrors);
|
||||
} else {
|
||||
$this->Controller->Flash->error($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($params['fields'])) {
|
||||
|
@ -1106,6 +1169,7 @@ class CRUDComponent extends Component
|
|||
throw new NotFoundException(__('Could not save {0} due to the input failing to meet expectations. Your input is bad and you should feel bad.', $this->ObjectAlias));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$exceptionMessage = $e->getMessage();
|
||||
$entity = false;
|
||||
}
|
||||
}
|
||||
|
@ -1123,7 +1187,7 @@ class CRUDComponent extends Component
|
|||
$isBulk,
|
||||
__('{0} deleted.', $this->ObjectAlias),
|
||||
__('All selected {0} have been deleted.', Inflector::pluralize($this->ObjectAlias)),
|
||||
__('Could not delete {0}.', $this->ObjectAlias),
|
||||
$exceptionMessage ?? __('Could not delete {0}.', $this->ObjectAlias),
|
||||
__(
|
||||
'{0} / {1} {2} have been deleted.',
|
||||
$bulkSuccesses,
|
||||
|
@ -1305,7 +1369,7 @@ class CRUDComponent extends Component
|
|||
if (!empty($additionalData['redirect'])) { // If a redirection occurs, we need to make sure the flash message gets displayed
|
||||
$this->Controller->Flash->error($message);
|
||||
}
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, $action, $data, $message, !is_null($errors) ? $errors : $data->getErrors());
|
||||
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, $action, $data, $message, $errors);
|
||||
} else {
|
||||
$this->Controller->Flash->error($message);
|
||||
$this->Controller->redirect($this->Controller->referer());
|
||||
|
|
|
@ -440,14 +440,19 @@ class RestResponseComponent extends Component
|
|||
return $this->viewData($response);
|
||||
}
|
||||
|
||||
public function ajaxFailResponse($ObjectAlias, $action, $entity, $message, $errors = [])
|
||||
public function ajaxFailResponse($ObjectAlias, $action, $entity = null, $message, $errors = [], $description = '')
|
||||
{
|
||||
$action = $this->__dissectAdminRouting($action);
|
||||
$entity = is_array($entity) ? $entity : $entity->toArray();
|
||||
if (empty($entity)) {
|
||||
$entity = [];
|
||||
} else {
|
||||
$entity = is_array($entity) ? $entity : $entity->toArray();
|
||||
}
|
||||
$response = [
|
||||
'success' => false,
|
||||
'message' => $message,
|
||||
'errors' => $errors,
|
||||
'description' => $description,
|
||||
'url' => !empty($entity['id']) ? $this->__generateURL($action, $ObjectAlias, $entity['id']) : ''
|
||||
];
|
||||
return $this->viewData($response);
|
||||
|
|
|
@ -78,7 +78,15 @@ class RolesController extends AppController
|
|||
|
||||
public function delete($id)
|
||||
{
|
||||
$this->CRUD->delete($id);
|
||||
$this->CRUD->delete($id, [
|
||||
'beforeSave' => function ($data) {
|
||||
$userCount = $this->Roles->Users->find()->where(['role_id' => $data['id']])->count();
|
||||
if ($userCount > 0) {
|
||||
throw new ForbiddenException(__('You cannot delete a role that has users assigned to it.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
]);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
|
|
|
@ -79,6 +79,10 @@ class UserSettingsController extends AppController
|
|||
if (empty($currentUser['role']['perm_community_admin'])) {
|
||||
$data['user_id'] = $currentUser->id;
|
||||
}
|
||||
$validationResult = $this->UserSettings->validateUserSetting($data, $currentUser);
|
||||
if (!$validationResult !== true) {
|
||||
throw new MethodNotAllowedException(__('You cannot create the given user setting. Reason: {0}', $validationResult));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
]);
|
||||
|
@ -131,6 +135,10 @@ class UserSettingsController extends AppController
|
|||
if ($data['user_id'] != $entity->user_id) {
|
||||
throw new MethodNotAllowedException(__('You cannot assign the setting to a different user.'));
|
||||
}
|
||||
$validationResult = $this->UserSettings->validateUserSetting($data);
|
||||
if ($validationResult !== true) {
|
||||
throw new MethodNotAllowedException(__('Setting value: {0}', $validationResult));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
]);
|
||||
|
@ -235,9 +243,10 @@ class UserSettingsController extends AppController
|
|||
public function saveMyBookmark()
|
||||
{
|
||||
if (!$this->request->is('get')) {
|
||||
$result = $this->UserSettings->saveBookmark($this->ACL->getUser(), $this->request->getData());
|
||||
$errors = null;
|
||||
$result = $this->UserSettings->saveBookmark($this->ACL->getUser(), $this->request->getData(), $errors);
|
||||
$success = !empty($result);
|
||||
$message = $success ? __('Bookmark saved') : __('Could not save bookmark');
|
||||
$message = $success ? __('Bookmark saved') : ($errors ?? __('Could not save bookmark'));
|
||||
$this->CRUD->setResponseForController('saveBookmark', $success, $message, $result);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
|
|
|
@ -86,10 +86,10 @@ class UsersController extends AppController
|
|||
$individual_ids = [];
|
||||
if (!$currentUser['role']['perm_community_admin']) {
|
||||
if ($currentUser['role']['perm_group_admin']) {
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0])->all()->toArray();
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_admin' => 0])->all()->toArray();
|
||||
$individual_ids = $this->Users->Individuals->find('aligned', ['organisation_id' => $currentUser['organisation_id']])->all()->extract('id')->toArray();
|
||||
} else {
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_org_admin' => 0])->all()->toArray();
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_org_admin' => 0, 'perm_admin' => 0])->all()->toArray();
|
||||
|
||||
}
|
||||
if (empty($individual_ids)) {
|
||||
|
@ -247,10 +247,10 @@ class UsersController extends AppController
|
|||
$validOrgIds = [];
|
||||
if (!$currentUser['role']['perm_community_admin']) {
|
||||
if ($currentUser['role']['perm_group_admin']) {
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0])->all()->toArray();
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_admin' => 0])->all()->toArray();
|
||||
$validOrgIds = $this->Users->Organisations->OrgGroups->getGroupOrgIdsForUser($currentUser);
|
||||
} else {
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_org_admin' => 0])->all()->toArray();
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_community_admin' => 0, 'perm_group_admin' => 0, 'perm_org_admin' => 0, 'perm_admin' => 0])->all()->toArray();
|
||||
}
|
||||
} else {
|
||||
$validRoles = $this->Users->Roles->find('list')->order(['name' => 'asc'])->all()->toArray();
|
||||
|
@ -320,10 +320,14 @@ class UsersController extends AppController
|
|||
}
|
||||
return $data;
|
||||
};
|
||||
$params['beforeSave'] = function ($data) use ($currentUser, $validRoles) {
|
||||
if (!in_array($data['role_id'], array_keys($validRoles)) && $this->ACL->getUser()['id'] != $data['id']) {
|
||||
$params['beforeSave'] = function ($data) use ($currentUser, $validRoles, $validOrgIds, $params) {
|
||||
// only run these checks if the user CAN edit them and if the values are actually set in the request
|
||||
if (in_array('role_id', $params['fields']) && isset($data['role_id']) && !in_array($data['role_id'], array_keys($validRoles)) && $this->ACL->getUser()['id'] != $data['id']) {
|
||||
throw new MethodNotAllowedException(__('You cannot assign the chosen role to a user.'));
|
||||
}
|
||||
if (in_array('organisation_id', $params['fields']) && isset($data['organisation_id']) && !in_array($data['organisation_id'], $validOrgIds)) {
|
||||
throw new MethodNotAllowedException(__('You cannot assign the chosen organisation to a user.'));
|
||||
}
|
||||
return $data;
|
||||
};
|
||||
}
|
||||
|
@ -487,7 +491,7 @@ class UsersController extends AppController
|
|||
{
|
||||
$editingAnotherUser = false;
|
||||
$currentUser = $this->ACL->getUser();
|
||||
if ((empty($currentUser['role']['perm_community_admin']) && empty($currentUser['role']['perm_group_admin'])) || $user_id == $currentUser->id) {
|
||||
if ((empty($currentUser['role']['perm_community_admin']) && empty($currentUser['role']['perm_group_admin'])) || empty($user_id) || $user_id == $currentUser->id) {
|
||||
$user = $currentUser;
|
||||
} else {
|
||||
$user = $this->Users->get($user_id, [
|
||||
|
|
|
@ -107,7 +107,7 @@ class CryptGpgExtended extends \Crypt_GPG
|
|||
$this->engine->reset();
|
||||
$this->engine->setInput($input);
|
||||
$this->engine->setOutput($output);
|
||||
$this->engine->setOperation('--import', ['--import-options', 'show-only', '--with-colons']);
|
||||
$this->engine->setOperation('--import', ['--import-options', 'show-only', '--with-colons', '--no-default-keyring --no-auto-check-trustdb --trust-model pgp']);
|
||||
$this->engine->run();
|
||||
|
||||
$keys = [];
|
||||
|
|
|
@ -93,4 +93,36 @@ class AuthKeysTable extends AppTable
|
|||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public function buildUserConditions($currentUser)
|
||||
{
|
||||
$conditions = [];
|
||||
$validOrgs = $this->Users->getValidOrgsForUser($currentUser);
|
||||
if (empty($currentUser['role']['perm_community_admin'])) {
|
||||
$conditions['Users.organisation_id IN'] = $validOrgs;
|
||||
if (empty($currentUser['role']['perm_group_admin'])) {
|
||||
if (empty($currentUser['role']['perm_org_admin'])) {
|
||||
$conditions['Users.id'] = $currentUser['id'];
|
||||
} else {
|
||||
$role_ids = $this->Users->Roles->find()->where(['perm_admin' => 0, 'perm_community_admin' => 0, 'perm_org_admin' => 0, 'perm_group_admin' => 0])->all()->extract('id')->toList();
|
||||
$conditions['Users.organisation_id'] = $currentUser['organisation_id'];
|
||||
$subConditions = [
|
||||
['Users.id' => $currentUser['id']]
|
||||
];
|
||||
if (!empty($role_ids)) {
|
||||
$subConditions[] = ['Users.role_id IN' => $role_ids];
|
||||
}
|
||||
$conditions['OR'] = $subConditions;
|
||||
}
|
||||
} else {
|
||||
$conditions['Users.group_id'] = $currentUser['group_id'];
|
||||
$role_ids = $this->Users->Roles->find()->where(['perm_admin' => 0, 'perm_community_admin' => 0, 'perm_group_admin' => 0])->all()->extract('id')->toList();
|
||||
$conditions['OR'] = [
|
||||
['Users.id' => $currentUser['id']],
|
||||
['Users.role_id IN' => $role_ids]
|
||||
];
|
||||
}
|
||||
}
|
||||
return $conditions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,10 +109,10 @@ class EncryptionKeysTable extends AppTable
|
|||
if (!$sortedKeys['valid']) {
|
||||
$result[2] = 'The user\'s PGP key does not include a valid subkey that could be used for encryption.';
|
||||
if ($sortedKeys['expired']) {
|
||||
$result[2] .= ' ' . __n('Found %s subkey that have expired.', 'Found %s subkeys that have expired.', $sortedKeys['expired'], $sortedKeys['expired']);
|
||||
$result[2] .= ' ' . __n(__('Found 1 subkey that has expired.'), __('Found {0} subkeys that have expired.', $sortedKeys['expired']), $sortedKeys['expired']);
|
||||
}
|
||||
if ($sortedKeys['noEncrypt']) {
|
||||
$result[2] .= ' ' . __n('Found %s subkey that is sign only.', 'Found %s subkeys that are sign only.', $sortedKeys['noEncrypt'], $sortedKeys['noEncrypt']);
|
||||
$result[2] .= ' ' . __n(__('Found 1 subkey that is sign only.'), __('Found {0} subkeys that are sign only.', $sortedKeys['noEncrypt']), $sortedKeys['noEncrypt']);
|
||||
}
|
||||
} else {
|
||||
$result[0] = true;
|
||||
|
|
|
@ -163,18 +163,22 @@ class BaseSettingsProvider
|
|||
$setting['error'] = false;
|
||||
if (!$skipValidation) {
|
||||
$validationResult = true;
|
||||
if (!isset($setting['value'])) {
|
||||
$validationResult = $this->settingValidator->testEmptyBecomesDefault(null, $setting);
|
||||
} else if (isset($setting['test'])) {
|
||||
$setting['value'] = $setting['value'] ?? '';
|
||||
$validationResult = $this->evaluateFunctionForSetting($setting['test'], $setting);
|
||||
}
|
||||
if ($validationResult !== true) {
|
||||
$setting['severity'] = $setting['severity'] ?? 'warning';
|
||||
if (!in_array($setting['severity'], $this->severities)) {
|
||||
$setting['severity'] = 'warning';
|
||||
if (empty($setting['value']) && !empty($setting['empty'])) {
|
||||
$validationResult = true;
|
||||
} else {
|
||||
if (!isset($setting['value'])) {
|
||||
$validationResult = $this->settingValidator->testEmptyBecomesDefault(null, $setting);
|
||||
} else if (isset($setting['test'])) {
|
||||
$setting['value'] = $setting['value'] ?? '';
|
||||
$validationResult = $this->evaluateFunctionForSetting($setting['test'], $setting);
|
||||
}
|
||||
if ($validationResult !== true) {
|
||||
$setting['severity'] = $setting['severity'] ?? 'warning';
|
||||
if (!in_array($setting['severity'], $this->severities)) {
|
||||
$setting['severity'] = 'warning';
|
||||
}
|
||||
$setting['errorMessage'] = $validationResult;
|
||||
}
|
||||
$setting['errorMessage'] = $validationResult;
|
||||
}
|
||||
$setting['error'] = $validationResult !== true ? true : false;
|
||||
}
|
||||
|
|
|
@ -136,15 +136,19 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
'Proxy' => [
|
||||
'Proxy.host' => [
|
||||
'name' => __('Host'),
|
||||
'severity' => 'info',
|
||||
'type' => 'string',
|
||||
'description' => __('The hostname of an HTTP proxy for outgoing sync requests. Leave empty to not use a proxy.'),
|
||||
'test' => 'testHostname',
|
||||
'empty' => true
|
||||
],
|
||||
'Proxy.port' => [
|
||||
'name' => __('Port'),
|
||||
'severity' => 'info',
|
||||
'type' => 'integer',
|
||||
'description' => __('The TCP port for the HTTP proxy.'),
|
||||
'test' => 'testForRangeXY',
|
||||
'empty' => true
|
||||
],
|
||||
'Proxy.user' => [
|
||||
'name' => __('User'),
|
||||
|
@ -152,6 +156,7 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
'description' => __('The authentication username for the HTTP proxy.'),
|
||||
'default' => 'admin',
|
||||
'dependsOn' => 'proxy.host',
|
||||
'empty' => true
|
||||
],
|
||||
'Proxy.password' => [
|
||||
'name' => __('Password'),
|
||||
|
@ -159,6 +164,7 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
'description' => __('The authentication password for the HTTP proxy.'),
|
||||
'default' => '',
|
||||
'dependsOn' => 'proxy.host',
|
||||
'empty' => true
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -338,6 +344,17 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
],
|
||||
]
|
||||
],
|
||||
'Restrictions' => [
|
||||
'Allowed bookmark domains' => [
|
||||
'security.restrictions.allowed_bookmark_domains' => [
|
||||
'name' => __('Allowed bookmark domains'),
|
||||
'type' => 'string',
|
||||
'severity' => 'info',
|
||||
'description' => __('Comma separated list of allowed bookmark domains. Leave empty to allow all domains.'),
|
||||
'default' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Development' => [
|
||||
'Debugging' => [
|
||||
'debug' => [
|
||||
|
@ -350,7 +367,7 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
true => __('Debug On'),
|
||||
],
|
||||
'test' => function ($value, $setting, $validator) {
|
||||
$validator->range('value', [0, 2]);
|
||||
$validator->range('value', [0, 1]);
|
||||
return testValidator($value, $validator);
|
||||
},
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Model\Table;
|
|||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
use Cake\Core\Configure;
|
||||
|
||||
require_once(APP . 'Model' . DS . 'Table' . DS . 'SettingProviders' . DS . 'UserSettingsProvider.php');
|
||||
use App\Settings\SettingsProvider\UserSettingsProvider;
|
||||
|
@ -94,14 +95,37 @@ class UserSettingsTable extends AppTable
|
|||
return $savedData;
|
||||
}
|
||||
|
||||
public function saveBookmark($user, $data)
|
||||
public function saveBookmark($user, $data, &$message = null)
|
||||
{
|
||||
$setting = $this->getSettingByName($user, $this->BOOKMARK_SETTING_NAME);
|
||||
$fieldsToCheck = [
|
||||
'bookmark_label' => __('Label'),
|
||||
'bookmark_name' => __('Name'),
|
||||
'bookmark_url' => __('URL')
|
||||
];
|
||||
foreach ($fieldsToCheck as $field => $fieldName) {
|
||||
if (empty($data[$field])) {
|
||||
$message = __('Please fill in all fields, {0} missing.', $fieldName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (empty($data['bookmark_label']) || empty($data['bookmark_name']) || empty($data['bookmark_url'])) {
|
||||
|
||||
return null;
|
||||
}
|
||||
$bookmarkData = [
|
||||
'label' => $data['bookmark_label'],
|
||||
'name' => $data['bookmark_name'],
|
||||
'url' => $data['bookmark_url'],
|
||||
];
|
||||
$restricted_domains = Configure::read('security.restrictions.allowed_bookmark_domains');
|
||||
if (!empty($restricted_domains)) {
|
||||
$restricted_domains = explode(',', $restricted_domains);
|
||||
$parsed = parse_url($bookmarkData['url']);
|
||||
if (!empty($parsed['host']) && !in_array($parsed['host'], $restricted_domains)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (is_null($setting)) { // setting not found, create it
|
||||
$bookmarksData = json_encode([$bookmarkData]);
|
||||
$result = $this->createSetting($user, $this->BOOKMARK_SETTING_NAME, $bookmarksData);
|
||||
|
@ -153,4 +177,40 @@ class UserSettingsTable extends AppTable
|
|||
}
|
||||
return $isLocalPath || $isValidURL;
|
||||
}
|
||||
|
||||
public function validateUserSetting($data): bool|string
|
||||
{
|
||||
$errors = [];
|
||||
$json_fields = ['ui.bookmarks'];
|
||||
if (in_array($data['name'], $json_fields)) {
|
||||
$decoded = json_decode($data['value'], true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
return __('Invalid JSON data');
|
||||
}
|
||||
$value = $decoded;
|
||||
} else {
|
||||
$value = $data['value'];
|
||||
}
|
||||
if ($data['name'] === 'ui.bookmarks') {
|
||||
if (array_values($value) !== $value) {
|
||||
$value = [$value];
|
||||
}
|
||||
$restricted_domains = Configure::read('security.restrictions.allowed_bookmark_domains');
|
||||
if (!empty($restricted_domains)) {
|
||||
$restricted_domains = explode(',', $restricted_domains);
|
||||
foreach ($restricted_domains as &$rd) {
|
||||
$rd = trim($rd);
|
||||
}
|
||||
}
|
||||
foreach ($value as $bookmark) {
|
||||
if (!empty($restricted_domains)) {
|
||||
$parsed = parse_url($bookmark['url']);
|
||||
if (!in_array($parsed['host'], $restricted_domains)) {
|
||||
return __('Invalid domain for bookmark. The only domains allowed are: {0}', implode(', ', $restricted_domains));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,7 +221,9 @@ class UsersTable extends AppTable
|
|||
'perm_admin' => 1,
|
||||
'perm_community_admin' => 1,
|
||||
'perm_org_admin' => 1,
|
||||
'perm_sync' => 1
|
||||
'perm_sync' => 1,
|
||||
'perm_group_admin' => 1,
|
||||
'perm_meta_field_editor' => 1
|
||||
]);
|
||||
$this->Roles->save($role);
|
||||
$this->Organisations = TableRegistry::get('Organisations');
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"version": "1.24",
|
||||
"version": "1.26",
|
||||
"application": "Cerebrate"
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
'data' => [
|
||||
'type' => 'simple',
|
||||
'text' => __('Add authentication key'),
|
||||
'popover_url' => '/authKeys/add',
|
||||
'reload_url' => $this->request->getRequestTarget()
|
||||
'popover_url' => '/authKeys/add' . ($action_query_strings ? '?' . http_build_query($action_query_strings) : ''),
|
||||
'reload_url' => $this->request->getRequestTarget(),
|
||||
]
|
||||
]
|
||||
],
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'data' => array(
|
||||
'description' => __('Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in genral require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them.'),
|
||||
'description' => __('Cerebrate can connect to other Cerebrate instances to exchange trust information and to instrument interconnectivity between connected local tools. Each such Cerebrate instance with its connected tools is considered to be a brood.'),
|
||||
'model' => 'Organisations',
|
||||
'fields' => array(
|
||||
array(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'data' => array(
|
||||
'description' => __('Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in genral require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them.'),
|
||||
'description' => __('Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in general require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them.'),
|
||||
'model' => 'Organisations',
|
||||
'fields' => array(
|
||||
array(
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
'label' => 'Site admin privilege (instance management)'
|
||||
],
|
||||
[
|
||||
'field' => 'perm_community',
|
||||
'field' => 'perm_community_admin',
|
||||
'type' => 'checkbox',
|
||||
'label' => 'Community admin privilege (data admin)'
|
||||
],
|
||||
|
|
|
@ -10,7 +10,7 @@ servers:
|
|||
|
||||
tags:
|
||||
- name: Individuals
|
||||
description: "Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in genral require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them."
|
||||
description: "Individuals are natural persons. They are meant to describe the basic information about an individual that may or may not be a user of this community. Users in general require an individual object to identify the person behind them - however, no user account is required to store information about an individual. Individuals can have affiliations to organisations and broods as well as cryptographic keys, using which their messages can be verified and which can be used to securely contact them."
|
||||
- name: Users
|
||||
description: "Users enrolled in this Cerebrate instance."
|
||||
- name: Organisations
|
||||
|
|
Loading…
Reference in New Issue