Merge branch 'develop' into main
commit
0dbdeee962
|
@ -68,6 +68,7 @@ class ACLComponent extends Component
|
|||
'view' => ['perm_admin']
|
||||
],
|
||||
'EncryptionKeys' => [
|
||||
'view' => ['*'],
|
||||
'add' => ['*'],
|
||||
'edit' => ['*'],
|
||||
'delete' => ['*'],
|
||||
|
|
|
@ -70,6 +70,12 @@ class InstanceController extends AppController
|
|||
usort($status, function($a, $b) {
|
||||
return strcmp($b['id'], $a['id']);
|
||||
});
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->RestResponse->viewData([
|
||||
'status' => $status,
|
||||
'updateAvailables' => $migrationStatus['updateAvailables'],
|
||||
], 'json');
|
||||
}
|
||||
$this->set('status', $status);
|
||||
$this->set('updateAvailables', $migrationStatus['updateAvailables']);
|
||||
}
|
||||
|
@ -140,6 +146,14 @@ class InstanceController extends AppController
|
|||
{
|
||||
$this->Settings = $this->getTableLocator()->get('Settings');
|
||||
$all = $this->Settings->getSettings(true);
|
||||
if ($this->ParamHandler->isRest()) {
|
||||
return $this->RestResponse->viewData([
|
||||
'settingsProvider' => $all['settingsProvider'],
|
||||
'settings' => $all['settings'],
|
||||
'settingsFlattened' => $all['settingsFlattened'],
|
||||
'notices' => $all['notices'],
|
||||
], 'json');
|
||||
}
|
||||
$this->set('settingsProvider', $all['settingsProvider']);
|
||||
$this->set('settings', $all['settings']);
|
||||
$this->set('settingsFlattened', $all['settingsFlattened']);
|
||||
|
|
|
@ -9,6 +9,8 @@ use \Cake\Database\Expression\QueryExpression;
|
|||
use Cake\Http\Exception\NotFoundException;
|
||||
use Cake\Http\Exception\MethodNotAllowedException;
|
||||
use Cake\Http\Exception\ForbiddenException;
|
||||
use Cake\Http\Exception\UnauthorizedException;
|
||||
|
||||
|
||||
class UserSettingsController extends AppController
|
||||
{
|
||||
|
@ -19,8 +21,12 @@ class UserSettingsController extends AppController
|
|||
public function index()
|
||||
{
|
||||
$conditions = [];
|
||||
$currentUser = $this->ACL->getUser();
|
||||
if (empty($currentUser['role']['perm_admin'])) {
|
||||
$conditions['user_id'] = $currentUser->id;
|
||||
}
|
||||
$this->CRUD->index([
|
||||
'conditions' => [],
|
||||
'conditions' => $conditions,
|
||||
'contain' => $this->containFields,
|
||||
'filters' => $this->filterFields,
|
||||
'quickFilters' => $this->quickFilterFields,
|
||||
|
@ -39,6 +45,9 @@ class UserSettingsController extends AppController
|
|||
|
||||
public function view($id)
|
||||
{
|
||||
if (!$this->isLoggedUserAllowedToEdit($id)) {
|
||||
throw new NotFoundException(__('Invalid {0}.', 'user setting'));
|
||||
}
|
||||
$this->CRUD->view($id, [
|
||||
'contain' => ['Users']
|
||||
]);
|
||||
|
@ -50,10 +59,13 @@ class UserSettingsController extends AppController
|
|||
|
||||
public function add($user_id = false)
|
||||
{
|
||||
$currentUser = $this->ACL->getUser();
|
||||
$this->CRUD->add([
|
||||
'redirect' => ['action' => 'index', $user_id],
|
||||
'beforeSave' => function($data) use ($user_id) {
|
||||
$data['user_id'] = $user_id;
|
||||
'beforeSave' => function ($data) use ($currentUser) {
|
||||
if (empty($currentUser['role']['perm_admin'])) {
|
||||
$data['user_id'] = $currentUser->id;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
]);
|
||||
|
@ -61,10 +73,13 @@ class UserSettingsController extends AppController
|
|||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$allUsers = $this->UserSettings->Users->find('list', ['keyField' => 'id', 'valueField' => 'username'])->order(['username' => 'ASC']);
|
||||
if (empty($currentUser['role']['perm_admin'])) {
|
||||
$allUsers->where(['id' => $currentUser->id]);
|
||||
$user_id = $currentUser->id;
|
||||
}
|
||||
$dropdownData = [
|
||||
'user' => $this->UserSettings->Users->find('list', [
|
||||
'sort' => ['username' => 'asc']
|
||||
]),
|
||||
'user' => $allUsers->all()->toArray(),
|
||||
];
|
||||
$this->set(compact('dropdownData'));
|
||||
$this->set('user_id', $user_id);
|
||||
|
@ -75,6 +90,11 @@ class UserSettingsController extends AppController
|
|||
$entity = $this->UserSettings->find()->where([
|
||||
'id' => $id
|
||||
])->first();
|
||||
|
||||
if (!$this->isLoggedUserAllowedToEdit($entity)) {
|
||||
throw new NotFoundException(__('Invalid {0}.', 'user setting'));
|
||||
}
|
||||
|
||||
$entity = $this->CRUD->edit($id, [
|
||||
'redirect' => ['action' => 'index', $entity->user_id]
|
||||
]);
|
||||
|
@ -94,6 +114,9 @@ class UserSettingsController extends AppController
|
|||
|
||||
public function delete($id)
|
||||
{
|
||||
if (!$this->isLoggedUserAllowedToEdit($id)) {
|
||||
throw new NotFoundException(__('Invalid {0}.', 'user setting'));
|
||||
}
|
||||
$this->CRUD->delete($id);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
|
@ -160,7 +183,7 @@ class UserSettingsController extends AppController
|
|||
}
|
||||
}
|
||||
|
||||
public function getBookmarks($forSidebar=false)
|
||||
public function getBookmarks($forSidebar = false)
|
||||
{
|
||||
$bookmarks = $this->UserSettings->getSettingByName($this->ACL->getUser(), $this->UserSettings->BOOKMARK_SETTING_NAME);
|
||||
$bookmarks = json_decode($bookmarks['value'], true);
|
||||
|
@ -200,4 +223,29 @@ class UserSettingsController extends AppController
|
|||
$this->set('user_id', $this->ACL->getUser()->id);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* isLoggedUserAllowedToEdit
|
||||
*
|
||||
* @param int|\App\Model\Entity\UserSetting $setting
|
||||
* @return boolean
|
||||
*/
|
||||
private function isLoggedUserAllowedToEdit($setting): bool
|
||||
{
|
||||
$currentUser = $this->ACL->getUser();
|
||||
$isAllowed = false;
|
||||
if (!empty($currentUser['role']['perm_admin'])) {
|
||||
$isAllowed = true;
|
||||
} else {
|
||||
if (is_numeric($setting)) {
|
||||
$setting = $this->UserSettings->find()->where([
|
||||
'id' => $setting
|
||||
])->first();
|
||||
if (empty($setting)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$isAllowed = $setting->user_id == $currentUser->id;
|
||||
}
|
||||
return $isAllowed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,11 @@ class MispConnector extends CommonConnectorTools
|
|||
'type' => 'boolean'
|
||||
],
|
||||
];
|
||||
public $settingsPlaceholder = [
|
||||
'url' => 'https://your.misp.intance',
|
||||
'authkey' => '',
|
||||
'skip_ssl' => '0',
|
||||
];
|
||||
|
||||
public function addSettingValidatorRules($validator)
|
||||
{
|
||||
|
|
|
@ -46,6 +46,22 @@ class SkeletonConnector extends CommonConnectorTools
|
|||
'redirect' => 'serverSettingsAction'
|
||||
]
|
||||
];
|
||||
public $settings = [
|
||||
'url' => [
|
||||
'type' => 'text'
|
||||
],
|
||||
'authkey' => [
|
||||
'type' => 'text'
|
||||
],
|
||||
'skip_ssl' => [
|
||||
'type' => 'boolean'
|
||||
],
|
||||
];
|
||||
public $settingsPlaceholder = [
|
||||
'url' => 'https://your.url',
|
||||
'authkey' => '',
|
||||
'skip_ssl' => '0',
|
||||
];
|
||||
|
||||
public function health(Object $connection): array
|
||||
{
|
||||
|
|
|
@ -143,7 +143,8 @@ class LocalToolsTable extends AppTable
|
|||
'connector' => $connector_type,
|
||||
'connector_version' => $connector_class->version,
|
||||
'connector_description' => $connector_class->description,
|
||||
'connector_settings' => $connector_class->settings ?? []
|
||||
'connector_settings' => $connector_class->settings ?? [],
|
||||
'connector_settings_placeholder' => $connector_class->settingsPlaceholder ?? [],
|
||||
];
|
||||
if ($includeConnections) {
|
||||
$connector['connections'] = $this->healthCheck($connector_type, $connector_class);
|
||||
|
|
|
@ -11,7 +11,7 @@ use App\Settings\SettingsProvider\UserSettingsProvider;
|
|||
|
||||
class UserSettingsTable extends AppTable
|
||||
{
|
||||
protected $BOOKMARK_SETTING_NAME = 'ui.bookmarks';
|
||||
public $BOOKMARK_SETTING_NAME = 'ui.bookmarks';
|
||||
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
|
|
|
@ -637,13 +637,13 @@ class BoostrapTable extends BootstrapGeneric {
|
|||
],
|
||||
]);
|
||||
foreach ($this->items as $i => $row) {
|
||||
$body .= $this->genRow($row);
|
||||
$body .= $this->genRow($row, $i);
|
||||
}
|
||||
$body .= $this->closeNode('tbody');
|
||||
return $body;
|
||||
}
|
||||
|
||||
private function genRow($row)
|
||||
private function genRow($row, $rowIndex)
|
||||
{
|
||||
$html = $this->openNode('tr',[
|
||||
'class' => [
|
||||
|
@ -658,21 +658,21 @@ class BoostrapTable extends BootstrapGeneric {
|
|||
$key = $field;
|
||||
}
|
||||
$cellValue = Hash::get($row, $key);
|
||||
$html .= $this->genCell($cellValue, $field, $row, $i);
|
||||
$html .= $this->genCell($cellValue, $field, $row, $rowIndex);
|
||||
}
|
||||
} else { // indexed array
|
||||
foreach ($row as $cellValue) {
|
||||
$html .= $this->genCell($cellValue, $field, $row, $i);
|
||||
foreach ($row as $i => $cellValue) {
|
||||
$html .= $this->genCell($cellValue, 'index', $row, $rowIndex);
|
||||
}
|
||||
}
|
||||
$html .= $this->closeNode('tr');
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function genCell($value, $field=[], $row=[], $i=0)
|
||||
private function genCell($value, $field=[], $row=[], $rowIndex=0)
|
||||
{
|
||||
if (isset($field['formatter'])) {
|
||||
$cellContent = $field['formatter']($value, $row, $i);
|
||||
$cellContent = $field['formatter']($value, $row, $rowIndex);
|
||||
} else if (isset($field['element'])) {
|
||||
$cellContent = $this->btHelper->getView()->element($field['element'], [
|
||||
'data' => [$value],
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
'codemirror' => [
|
||||
'height' => '10rem',
|
||||
'hints' => $connectors[0]['connector_settings']
|
||||
]
|
||||
],
|
||||
'placeholder' => json_encode($connectors[0]['connector_settings_placeholder'], JSON_FORCE_OBJECT | JSON_PRETTY_PRINT)
|
||||
],
|
||||
[
|
||||
'field' => 'description',
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
array(
|
||||
'field' => 'name'
|
||||
),
|
||||
array(
|
||||
'field' => 'description',
|
||||
'type' => 'textarea'
|
||||
),
|
||||
array(
|
||||
'field' => 'uuid',
|
||||
'label' => 'UUID',
|
||||
|
|
|
@ -52,6 +52,7 @@ $sidebarOpen = $loggedUser->user_settings_by_name_with_fallback['ui.sidebar.expa
|
|||
<?= $this->Html->script('CodeMirror/addon/lint/json-lint') ?>
|
||||
<?= $this->Html->script('CodeMirror/addon/edit/matchbrackets') ?>
|
||||
<?= $this->Html->script('CodeMirror/addon/edit/closebrackets') ?>
|
||||
<?= $this->Html->script('CodeMirror/addon/display/placeholder') ?>
|
||||
<?= $this->Html->css('CodeMirror/codemirror') ?>
|
||||
<?= $this->Html->css('CodeMirror/codemirror-additional') ?>
|
||||
<?= $this->Html->css('CodeMirror/addon/hint/show-hint') ?>
|
||||
|
|
|
@ -26,4 +26,8 @@
|
|||
|
||||
.CodeMirror-hints {
|
||||
z-index: 1060 !important; /* Make sure hint is above modal */
|
||||
}
|
||||
|
||||
.CodeMirror pre.CodeMirror-placeholder {
|
||||
color: #999;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
||||
(function (mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function (CodeMirror) {
|
||||
CodeMirror.defineOption("placeholder", "", function (cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
cm.on("blur", onBlur);
|
||||
cm.on("change", onChange);
|
||||
cm.on("swapDoc", onChange);
|
||||
CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = function () { onComposition(cm) })
|
||||
onChange(cm);
|
||||
} else if (!val && prev) {
|
||||
cm.off("blur", onBlur);
|
||||
cm.off("change", onChange);
|
||||
cm.off("swapDoc", onChange);
|
||||
CodeMirror.off(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose)
|
||||
clearPlaceholder(cm);
|
||||
var wrapper = cm.getWrapperElement();
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
|
||||
}
|
||||
|
||||
if (val && !cm.hasFocus()) onBlur(cm);
|
||||
});
|
||||
|
||||
function clearPlaceholder(cm) {
|
||||
if (cm.state.placeholder) {
|
||||
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
|
||||
cm.state.placeholder = null;
|
||||
}
|
||||
}
|
||||
function setPlaceholder(cm) {
|
||||
clearPlaceholder(cm);
|
||||
var elt = cm.state.placeholder = document.createElement("pre");
|
||||
elt.style.cssText = "height: 0; overflow: visible";
|
||||
elt.style.direction = cm.getOption("direction");
|
||||
elt.className = "CodeMirror-placeholder CodeMirror-line-like";
|
||||
var placeHolder = cm.getOption("placeholder")
|
||||
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
|
||||
elt.appendChild(placeHolder)
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
|
||||
}
|
||||
|
||||
function onComposition(cm) {
|
||||
setTimeout(function () {
|
||||
var empty = false
|
||||
if (cm.lineCount() == 1) {
|
||||
var input = cm.getInputField()
|
||||
empty = input.nodeName == "TEXTAREA" ? !cm.getLine(0).length
|
||||
: !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent)
|
||||
}
|
||||
if (empty) setPlaceholder(cm)
|
||||
else clearPlaceholder(cm)
|
||||
}, 20)
|
||||
}
|
||||
|
||||
function onBlur(cm) {
|
||||
if (isEmpty(cm)) setPlaceholder(cm);
|
||||
}
|
||||
function onChange(cm) {
|
||||
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
|
||||
|
||||
if (empty) setPlaceholder(cm);
|
||||
else clearPlaceholder(cm);
|
||||
}
|
||||
|
||||
function isEmpty(cm) {
|
||||
return (cm.lineCount() === 1) && (cm.getLine(0) === "");
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue