Merge branch 'develop' into main

pull/92/head
iglocska 2022-01-18 08:17:44 +01:00
commit 0dbdeee962
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
13 changed files with 187 additions and 22 deletions

View File

@ -68,6 +68,7 @@ class ACLComponent extends Component
'view' => ['perm_admin']
],
'EncryptionKeys' => [
'view' => ['*'],
'add' => ['*'],
'edit' => ['*'],
'delete' => ['*'],

View File

@ -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']);

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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
{

View File

@ -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);

View File

@ -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
{

View File

@ -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],

View File

@ -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',

View File

@ -7,10 +7,6 @@
array(
'field' => 'name'
),
array(
'field' => 'description',
'type' => 'textarea'
),
array(
'field' => 'uuid',
'label' => 'UUID',

View File

@ -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') ?>

View File

@ -26,4 +26,8 @@
.CodeMirror-hints {
z-index: 1060 !important; /* Make sure hint is above modal */
}
.CodeMirror pre.CodeMirror-placeholder {
color: #999;
}

View File

@ -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) === "");
}
});