Merge branch 'develop' of github.com:cerebrate-project/cerebrate into develop
commit
f6900b0843
|
@ -84,7 +84,7 @@ class AuthKeysController extends AppController
|
|||
'displayOnSuccess' => 'authkey_display',
|
||||
'beforeSave' => function($data) use ($users) {
|
||||
if (!in_array($data['user_id'], array_keys($users))) {
|
||||
return false;
|
||||
throw new MethodNotAllowedException(__('You are not authorised to do that.'));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
|
|
@ -169,6 +169,12 @@ class CRUDComponent extends Component
|
|||
if (!empty($params['fields'])) {
|
||||
$patchEntityParams['fields'] = $params['fields'];
|
||||
}
|
||||
if (isset($params['beforeMarshal'])) {
|
||||
$input = $params['beforeMarshal']($input);
|
||||
if ($input === false) {
|
||||
throw new NotFoundException(__('Could not save {0} due to the marshaling failing. Your input is bad and you should feel bad.', $this->ObjectAlias));
|
||||
}
|
||||
}
|
||||
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
|
||||
if (isset($params['beforeSave'])) {
|
||||
$data = $params['beforeSave']($data);
|
||||
|
@ -310,9 +316,18 @@ class CRUDComponent extends Component
|
|||
if (!empty($params['fields'])) {
|
||||
$patchEntityParams['fields'] = $params['fields'];
|
||||
}
|
||||
if (isset($params['beforeMarshal'])) {
|
||||
$input = $params['beforeMarshal']($input);
|
||||
if ($input === false) {
|
||||
throw new NotFoundException(__('Could not save {0} due to the marshaling failing. Your input is bad and you should feel bad.', $this->ObjectAlias));
|
||||
}
|
||||
}
|
||||
$data = $this->Table->patchEntity($data, $input, $patchEntityParams);
|
||||
if (isset($params['beforeSave'])) {
|
||||
$data = $params['beforeSave']($data);
|
||||
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));
|
||||
}
|
||||
}
|
||||
$savedData = $this->Table->save($data);
|
||||
if ($savedData !== false) {
|
||||
|
|
|
@ -17,7 +17,14 @@ class FloodProtectionComponent extends Component
|
|||
public function initialize(array $config): void
|
||||
{
|
||||
$ip_source = Configure::check('security.logging.ip_source') ? Configure::read('security.logging.ip_source') : 'REMOTE_ADDR';
|
||||
if (!isset($_SERVER[$ip_source])) {
|
||||
$ip_source = 'REMOTE_ADDR';
|
||||
}
|
||||
if (isset($_SERVER[$ip_source])) {
|
||||
$this->remote_ip = $_SERVER[$ip_source];
|
||||
} else {
|
||||
$this->remote_ip = '127.0.0.1';
|
||||
}
|
||||
$temp = explode(PHP_EOL, $_SERVER[$ip_source]);
|
||||
if (count($temp) > 1) {
|
||||
$this->remote_ip = $temp[0];
|
||||
|
|
|
@ -37,10 +37,17 @@ class SharingGroupsController extends AppController
|
|||
|
||||
public function add()
|
||||
{
|
||||
$currentUser = $this->ACL->getUser();
|
||||
$this->CRUD->add([
|
||||
'override' => [
|
||||
'user_id' => $this->ACL->getUser()['id']
|
||||
]
|
||||
],
|
||||
'beforeSave' => function($data) use ($currentUser) {
|
||||
if (!$currentUser['role']['perm_admin']) {
|
||||
$data['organisation_id'] = $currentUser['organisation_id'];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
]);
|
||||
$dropdownData = [
|
||||
'organisation' => $this->getAvailableOrgForSg($this->ACL->getUser())
|
||||
|
|
|
@ -9,6 +9,7 @@ use \Cake\Database\Expression\QueryExpression;
|
|||
use Cake\Http\Exception\UnauthorizedException;
|
||||
use Cake\Http\Exception\MethodNotAllowedException;
|
||||
use Cake\Core\Configure;
|
||||
use Cake\Utility\Security;
|
||||
|
||||
class UsersController extends AppController
|
||||
{
|
||||
|
@ -44,15 +45,30 @@ class UsersController extends AppController
|
|||
{
|
||||
$currentUser = $this->ACL->getUser();
|
||||
$validRoles = [];
|
||||
$individuals_params = [
|
||||
'sort' => ['email' => 'asc']
|
||||
];
|
||||
$individual_ids = [];
|
||||
if (!$currentUser['role']['perm_admin']) {
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_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 {
|
||||
$validRoles = $this->Users->Roles->find('list')->order(['name' => 'asc'])->all()->toArray();
|
||||
}
|
||||
$defaultRole = $this->Users->Roles->find()->select(['id'])->first()->toArray();
|
||||
|
||||
$individuals = $this->Users->Individuals->find('list', $individuals_params)->toArray();
|
||||
$this->CRUD->add([
|
||||
'beforeSave' => function($data) use ($currentUser, $validRoles, $defaultRole) {
|
||||
'beforeMarshal' => function($data) {
|
||||
if (empty($data['password'])) {
|
||||
$data['password'] = Security::randomString(20);
|
||||
}
|
||||
return $data;
|
||||
},
|
||||
'beforeSave' => function($data) use ($currentUser, $validRoles, $defaultRole, $individual_ids) {
|
||||
if (!isset($data['role_id']) && !empty($defaultRole)) {
|
||||
$data['role_id'] = $defaultRole['id'];
|
||||
}
|
||||
|
@ -62,6 +78,21 @@ class UsersController extends AppController
|
|||
throw new MethodNotAllowedException(__('You do not have permission to assign that role.'));
|
||||
}
|
||||
}
|
||||
if ((!isset($data['individual_id']) || $data['individual_id'] === 'new') && !empty($data['individual'])) {
|
||||
$existingOrg = $this->Users->Organisations->find('all')->where(['id' => $data['organisation_id']])->select(['uuid'])->first();
|
||||
if (empty($existingOrg)) {
|
||||
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_id'] = $this->Users->Individuals->captureIndividual($data['individual']);
|
||||
} else if (!$currentUser['role']['perm_admin'] && isset($data['individual_id'])) {
|
||||
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.'));
|
||||
}
|
||||
}
|
||||
if (empty($data['individual_id'])) {
|
||||
throw new MethodNotAllowedException(__('No valid individual found. Either supply it in the request or set the individual_id to a valid value.'));
|
||||
}
|
||||
$this->Users->enrollUserRouter($data);
|
||||
return $data;
|
||||
}
|
||||
|
@ -84,9 +115,7 @@ class UsersController extends AppController
|
|||
}
|
||||
$dropdownData = [
|
||||
'role' => $validRoles,
|
||||
'individual' => $this->Users->Individuals->find('list', [
|
||||
'sort' => ['email' => 'asc']
|
||||
]),
|
||||
'individual' => $individuals,
|
||||
'organisation' => $this->Users->Organisations->find('list', [
|
||||
'sort' => ['name' => 'asc'],
|
||||
'conditions' => $org_conditions
|
||||
|
@ -118,7 +147,7 @@ class UsersController extends AppController
|
|||
$currentUser = $this->ACL->getUser();
|
||||
$validRoles = [];
|
||||
if (!$currentUser['role']['perm_admin']) {
|
||||
$validRoles = $this->Users->Roles->find('list')->select(['id', 'name'])->order(['name' => 'asc'])->where(['perm_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();
|
||||
} else {
|
||||
$validRoles = $this->Users->Roles->find('list')->order(['name' => 'asc'])->all()->toArray();
|
||||
}
|
||||
|
@ -136,7 +165,7 @@ class UsersController extends AppController
|
|||
$params = [
|
||||
'get' => [
|
||||
'fields' => [
|
||||
'id', 'individual_id', 'role_id', 'username', 'disabled'
|
||||
'id', 'individual_id', 'role_id', 'disabled', 'username'
|
||||
]
|
||||
],
|
||||
'removeEmpty' => [
|
||||
|
@ -148,12 +177,10 @@ class UsersController extends AppController
|
|||
];
|
||||
if (!empty($this->ACL->getUser()['role']['perm_admin'])) {
|
||||
$params['fields'][] = 'individual_id';
|
||||
$params['fields'][] = 'username';
|
||||
$params['fields'][] = 'role_id';
|
||||
$params['fields'][] = 'organisation_id';
|
||||
$params['fields'][] = 'disabled';
|
||||
} else if (!empty($this->ACL->getUser()['role']['perm_org_admin'])) {
|
||||
$params['fields'][] = 'username';
|
||||
$params['fields'][] = 'role_id';
|
||||
$params['fields'][] = 'disabled';
|
||||
if (!$currentUser['role']['perm_admin']) {
|
||||
|
@ -166,6 +193,12 @@ class UsersController extends AppController
|
|||
}
|
||||
return $data;
|
||||
};
|
||||
$params['beforeSave'] = function ($data) use ($currentUser, $validRoles) {
|
||||
if (!in_array($data['role_id'], array_keys($validRoles))) {
|
||||
throw new MethodNotAllowedException(__('You cannot assign the chosen role to a user.'));
|
||||
}
|
||||
return $data;
|
||||
};
|
||||
}
|
||||
}
|
||||
$this->CRUD->edit($id, $params);
|
||||
|
@ -311,7 +344,7 @@ class UsersController extends AppController
|
|||
if (empty(Configure::read('security.registration.self-registration'))) {
|
||||
throw new UnauthorizedException(__('User self-registration is not open.'));
|
||||
}
|
||||
if (!empty(Configure::read('security.registration.floodProtection'))) {
|
||||
if (!Configure::check('security.registration.floodProtection') || Configure::read('security.registration.floodProtection')) {
|
||||
$this->FloodProtection->check('register');
|
||||
}
|
||||
if ($this->request->is('post')) {
|
||||
|
|
|
@ -132,9 +132,9 @@ class MispConnector extends CommonConnectorTools
|
|||
{
|
||||
return $validator
|
||||
->requirePresence('url')
|
||||
->notEmpty('url', __('An URL must be provided'))
|
||||
->notEmptyString('url', __('An URL must be provided'))
|
||||
->requirePresence('authkey')
|
||||
->notEmpty('authkey', __('An Authkey must be provided'))
|
||||
->notEmptyString('authkey', __('An Authkey must be provided'))
|
||||
->lengthBetween('authkey', [40, 40], __('The authkey must be 40 character long'))
|
||||
->boolean('skip_ssl');
|
||||
}
|
||||
|
|
|
@ -137,6 +137,30 @@ class AuthKeycloakBehavior extends Behavior
|
|||
]
|
||||
]
|
||||
);
|
||||
$logChange = [
|
||||
'username' => $data['username'],
|
||||
'individual_id' => $data['individual_id'],
|
||||
'role_id' => $data['role_id']
|
||||
];
|
||||
if (!$response->isOk()) {
|
||||
$logChange['error_code'] = $response->getStatusCode();
|
||||
$logChange['error_body'] = $response->getStringBody();
|
||||
$this->_table->auditLogs()->insert([
|
||||
'request_action' => 'enrollUser',
|
||||
'model' => 'User',
|
||||
'model_id' => 0,
|
||||
'model_title' => __('Failed Keycloak enrollment for user {0}', $data['username']),
|
||||
'changed' => $logChange
|
||||
]);
|
||||
} else {
|
||||
$this->_table->auditLogs()->insert([
|
||||
'request_action' => 'enrollUser',
|
||||
'model' => 'User',
|
||||
'model_id' => 0,
|
||||
'model_title' => __('Successful Keycloak enrollment for user {0}', $data['username']),
|
||||
'changed' => $logChange
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ class AlignmentsTable extends AppTable
|
|||
'type' => $type
|
||||
];
|
||||
$this->patchEntity($alignment, $data);
|
||||
$this->save($alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ namespace App\Model\Table;
|
|||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
use Cake\ORM\Query;
|
||||
|
||||
|
||||
class IndividualsTable extends AppTable
|
||||
{
|
||||
|
@ -55,7 +57,9 @@ class IndividualsTable extends AppTable
|
|||
'uuid' => $individual['uuid']
|
||||
])->first();
|
||||
} else {
|
||||
return null;
|
||||
$existingIndividual = $this->find()->where([
|
||||
'email' => $individual['email']
|
||||
])->first();
|
||||
}
|
||||
if (empty($existingIndividual)) {
|
||||
$entityToSave = $this->newEmptyEntity();
|
||||
|
@ -90,4 +94,16 @@ class IndividualsTable extends AppTable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function findAligned(Query $query, array $options)
|
||||
{
|
||||
$query = $query->select(['Individuals.id']);
|
||||
if (empty($options['organisation_id'])) {
|
||||
$query->leftJoinWith('Alignments')->where(['Alignments.organisation_id IS' => null]);
|
||||
} else {
|
||||
$query->innerJoinWith('Alignments')
|
||||
->where(['Alignments.organisation_id IN' => $options['organisation_id']]);
|
||||
}
|
||||
return $query->group(['Individuals.id', 'Individuals.uuid']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ require_once(APP . 'Model' . DS . 'Table' . DS . 'SettingProviders' . DS . 'Base
|
|||
|
||||
use App\Settings\SettingsProvider\BaseSettingsProvider;
|
||||
use App\Settings\SettingsProvider\SettingValidator;
|
||||
use Cake\Core\Configure;
|
||||
|
||||
class CerebrateSettingsProvider extends BaseSettingsProvider
|
||||
{
|
||||
|
@ -150,6 +151,17 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
],
|
||||
'Authentication' => [
|
||||
'Providers' => [
|
||||
'PasswordAuth' => [
|
||||
'password_auth.enabled' => [
|
||||
'name' => 'Disable password authentication',
|
||||
'type' => 'boolean',
|
||||
'severity' => 'warning',
|
||||
'description' => __('Enable username/password authentication.'),
|
||||
'default' => true,
|
||||
'test' => 'testEnabledAuth',
|
||||
'authentication_type' => 'password_auth'
|
||||
],
|
||||
],
|
||||
'KeyCloak' => [
|
||||
'keycloak.enabled' => [
|
||||
'name' => 'Enabled',
|
||||
|
@ -157,6 +169,8 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
'severity' => 'warning',
|
||||
'description' => __('Enable keycloak authentication'),
|
||||
'default' => false,
|
||||
'test' => 'testEnabledAuth',
|
||||
'authentication_type' => 'keycloak'
|
||||
],
|
||||
'keycloak.provider.applicationId' => [
|
||||
'name' => 'Client ID',
|
||||
|
@ -300,8 +314,10 @@ class CerebrateSettingsProvider extends BaseSettingsProvider
|
|||
'security.registration.floodProtection' => [
|
||||
'name' => __('Enable registration flood-protection'),
|
||||
'type' => 'boolean',
|
||||
'description' => __('Enabling this setting will only allow 5 registrations / IP address every 15 minutes (rolling time-frame).'),
|
||||
'default' => false,
|
||||
'description' => (Configure::check('security.logging.ip_source') && Configure::read('security.logging.ip_source') !== 'REMOTE_ADDR') ?
|
||||
__('Enabling this setting will only allow 5 registrations / IP address every 15 minutes (rolling time-frame). WARNING: Be aware that you are not using REMOTE_ADDR (as configured via security.logging.ip_source) - this could lead to an attacker being able to spoof their IP and circumvent the flood protection. Only rely on the client IP if your reverse proxy in front of Cerebrate is properly setting this header.'):
|
||||
__('Enabling this setting will only allow 5 registrations / IP address every 15 minutes (rolling time-frame).'),
|
||||
'default' => true,
|
||||
],
|
||||
]
|
||||
],
|
||||
|
@ -371,4 +387,24 @@ class CerebrateSettingValidator extends SettingValidator
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function testEnabledAuth($value, &$setting)
|
||||
{
|
||||
$providers = [
|
||||
'password_auth',
|
||||
'keycloak'
|
||||
];
|
||||
if (!$value) {
|
||||
$foundEnabledAuth = __('Cannot make change - this would disable every possible authentication method.');
|
||||
foreach ($providers as $provider) {
|
||||
if ($provider !== $setting['authentication_type']) {
|
||||
if (Configure::read($provider . '.enabled')) {
|
||||
$foundEnabledAuth = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $foundEnabledAuth;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
<?php
|
||||
use Cake\Core\Configure;
|
||||
$passwordRequired = false;
|
||||
if ($this->request->getParam('action') === 'add') {
|
||||
$dropdownData['individual'] = ['new' => __('New individual')] + $dropdownData['individual'];
|
||||
if (!Configure::check('password_auth.enabled') || Configure::read('password_auth.enabled')) {
|
||||
$passwordRequired = 'required';
|
||||
}
|
||||
}
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'description' => __('Roles define global rules for a set of users, including first and foremost access controls to certain functionalities.'),
|
||||
|
@ -10,6 +18,32 @@
|
|||
'label' => __('Associated individual'),
|
||||
'options' => $dropdownData['individual']
|
||||
],
|
||||
[
|
||||
'field' => 'individual.email',
|
||||
'stateDependence' => [
|
||||
'source' => '#individual_id-field',
|
||||
'option' => 'new'
|
||||
],
|
||||
'required' => false
|
||||
],
|
||||
[
|
||||
'field' => 'individual.first_name',
|
||||
'label' => 'First name',
|
||||
'stateDependence' => [
|
||||
'source' => '#individual_id-field',
|
||||
'option' => 'new'
|
||||
],
|
||||
'required' => false
|
||||
],
|
||||
[
|
||||
'field' => 'individual.last_name',
|
||||
'label' => 'Last name',
|
||||
'stateDependence' => [
|
||||
'source' => '#individual_id-field',
|
||||
'option' => 'new'
|
||||
],
|
||||
'required' => false
|
||||
],
|
||||
[
|
||||
'field' => 'username',
|
||||
'autocomplete' => 'off'
|
||||
|
@ -25,16 +59,18 @@
|
|||
'field' => 'password',
|
||||
'label' => __('Password'),
|
||||
'type' => 'password',
|
||||
'required' => $this->request->getParam('action') === 'add' ? 'required' : false,
|
||||
'required' => $passwordRequired,
|
||||
'autocomplete' => 'new-password',
|
||||
'value' => ''
|
||||
'value' => '',
|
||||
'requirements' => (bool)$passwordRequired
|
||||
],
|
||||
[
|
||||
'field' => 'confirm_password',
|
||||
'label' => __('Confirm Password'),
|
||||
'type' => 'password',
|
||||
'required' => $this->request->getParam('action') === 'add' ? 'required' : false,
|
||||
'autocomplete' => 'off'
|
||||
'required' => $passwordRequired,
|
||||
'autocomplete' => 'off',
|
||||
'requirements' => (bool)$passwordRequired
|
||||
],
|
||||
[
|
||||
'field' => 'role_id',
|
||||
|
|
|
@ -12,13 +12,14 @@ use Cake\Core\Configure;
|
|||
'style' => ['filter: drop-shadow(4px 4px 4px #924da666);']
|
||||
])
|
||||
);
|
||||
echo sprintf('<h4 class="text-uppercase fw-light mb-3">%s</h4>', __('Sign In'));
|
||||
$template = [
|
||||
'inputContainer' => '<div class="form-floating input {{type}}{{required}}">{{content}}</div>',
|
||||
'formGroup' => '{{input}}{{label}}',
|
||||
'submitContainer' => '<div class="submit d-grid">{{content}}</div>',
|
||||
];
|
||||
$this->Form->setTemplates($template);
|
||||
if (!Configure::check('password_auth.enabled') || Configure::read('password_auth.enabled')) {
|
||||
echo sprintf('<h4 class="text-uppercase fw-light mb-3">%s</h4>', __('Sign In'));
|
||||
echo $this->Form->create(null, ['url' => ['controller' => 'users', 'action' => 'login']]);
|
||||
echo $this->Form->control('username', ['label' => 'Username', 'class' => 'form-control mb-2', 'placeholder' => __('Username')]);
|
||||
echo $this->Form->control('password', ['type' => 'password', 'label' => 'Password', 'class' => 'form-control mb-3', 'placeholder' => __('Password')]);
|
||||
|
@ -26,12 +27,14 @@ use Cake\Core\Configure;
|
|||
echo $this->Form->end();
|
||||
if (!empty(Configure::read('security.registration.self-registration'))) {
|
||||
echo '<div class="text-end">';
|
||||
echo sprintf('<span class="text-secondary ms-auto" style="font-size: 0.8rem">%s <a href="/users/register" class="text-decoration-none link-primary fw-bold">%s</a></span>', __('Doesn\'t have an account?'), __('Sign up'));
|
||||
echo sprintf('<span class="text-secondary ms-auto" style="font-size: 0.8rem">%s <a href="/users/register" class="text-decoration-none link-primary fw-bold">%s</a></span>', __('Don\'t have an account?'), __('Sign up'));
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
if (!empty(Configure::read('keycloak.enabled'))) {
|
||||
echo sprintf('<div class="d-flex align-items-center my-2"><hr class="d-inline-block flex-grow-1"/><span class="mx-3 fw-light">%s</span><hr class="d-inline-block flex-grow-1"/></div>', __('Or'));
|
||||
}
|
||||
}
|
||||
if (!empty(Configure::read('keycloak.enabled'))) {
|
||||
echo $this->Form->create(null, [
|
||||
'url' => Cake\Routing\Router::url([
|
||||
'prefix' => false,
|
||||
|
|
|
@ -17,8 +17,11 @@ echo $this->element(
|
|||
'path' => 'username'
|
||||
],
|
||||
[
|
||||
'type' => 'generic',
|
||||
'key' => __('Email'),
|
||||
'path' => 'individual.email'
|
||||
'path' => 'individual.email',
|
||||
'url' => '/individuals/view/{{0}}',
|
||||
'url_vars' => 'individual_id'
|
||||
],
|
||||
[
|
||||
'type' => 'generic',
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
);
|
||||
}
|
||||
$reload_url = !empty($action['reload_url']) ? $action['reload_url'] : $this->Url->build(['action' => 'index']);
|
||||
$action['onclick'] = sprintf('UI.submissionModalForIndex(\'%s\', \'%s\', \'%s\')', $modal_url, $reload_url, $tableRandomValue);
|
||||
$action['onclick'] = sprintf('UI.submissionModalForIndex(\'%s\', \'%s\', \'%s\')', h($modal_url), h($reload_url), h($tableRandomValue));
|
||||
}
|
||||
echo sprintf(
|
||||
'<a href="%s" title="%s" aria-label="%s" %s %s class="btn btn-sm btn-outline-dark table-link-action"><i class="%s"></i></a> ',
|
||||
|
|
|
@ -18,7 +18,11 @@ $form = $this->element('genericElements/Form/genericForm', [
|
|||
]);
|
||||
$formHTML = sprintf('<div class="d-none">%s</div>', $form);
|
||||
|
||||
$bodyMessage = !empty($deletionText) ? __($deletionText) : __('Are you sure you want to delete {0} #{1}?', h(Cake\Utility\Inflector::singularize($this->request->getParam('controller'))), h($id));
|
||||
if (!empty($id)) {
|
||||
$bodyMessage = !empty($deletionText) ? __($deletionText) : __('Are you sure you want to delete {0} #{1}?', h(Cake\Utility\Inflector::singularize($this->request->getParam('controller'))), h($id));
|
||||
} else {
|
||||
$bodyMessage = !empty($deletionText) ? __($deletionText) : __('Are you sure you want to delete the given {0}?', h(Cake\Utility\Inflector::singularize($this->request->getParam('controller'))));
|
||||
}
|
||||
$bodyHTML = sprintf('%s%s', $formHTML, $bodyMessage);
|
||||
|
||||
echo $this->Bootstrap->modal([
|
||||
|
|
|
@ -65,8 +65,7 @@ class AddAuthKeyApiTest extends TestCase
|
|||
]
|
||||
);
|
||||
|
||||
$this->assertResponseCode(404);
|
||||
$this->addWarning('Should return 405 Method Not Allowed instead of 404 Not Found');
|
||||
$this->assertResponseCode(405);
|
||||
$this->assertDbRecordNotExists('AuthKeys', ['uuid' => $uuid]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue