Merge branch 'develop' into add-integration-tests

pull/80/head
Luciano Righetti 2022-01-18 14:29:54 +01:00
commit f48c1a5a17
29 changed files with 410 additions and 95 deletions

Binary file not shown.

Binary file not shown.

View File

@ -10,22 +10,22 @@ class TagSystem extends AbstractMigration
$tags = $this->table('tags_tags'); $tags = $this->table('tags_tags');
$tags->addColumn('namespace', 'string', [ $tags->addColumn('namespace', 'string', [
'default' => null, 'default' => null,
'limit' => 255, 'limit' => 191,
'null' => true, 'null' => true,
]) ])
->addColumn('predicate', 'string', [ ->addColumn('predicate', 'string', [
'default' => null, 'default' => null,
'limit' => 255, 'limit' => 191,
'null' => true, 'null' => true,
]) ])
->addColumn('value', 'string', [ ->addColumn('value', 'string', [
'default' => null, 'default' => null,
'limit' => 255, 'limit' => 191,
'null' => true, 'null' => true,
]) ])
->addColumn('name', 'string', [ ->addColumn('name', 'string', [
'default' => null, 'default' => null,
'limit' => 255, 'limit' => 191,
'null' => false, 'null' => false,
]) ])
->addColumn('colour', 'string', [ ->addColumn('colour', 'string', [
@ -66,7 +66,7 @@ class TagSystem extends AbstractMigration
]) ])
->addColumn('fk_model', 'string', [ ->addColumn('fk_model', 'string', [
'default' => null, 'default' => null,
'limit' => 255, 'limit' => 191,
'null' => false, 'null' => false,
'comment' => 'The model name of the entity being tagged' 'comment' => 'The model name of the entity being tagged'
]) ])

View File

@ -114,7 +114,6 @@ class TagBehavior extends Behavior
$property = $this->getConfig('tagsAssoc.propertyName'); $property = $this->getConfig('tagsAssoc.propertyName');
$options['accessibleFields'][$property] = true; $options['accessibleFields'][$property] = true;
$options['associated']['Tags']['accessibleFields']['id'] = true; $options['associated']['Tags']['accessibleFields']['id'] = true;
if (isset($data['tags'])) { if (isset($data['tags'])) {
if (!empty($data['tags'])) { if (!empty($data['tags'])) {
$data[$property] = $this->normalizeTags($data['tags']); $data[$property] = $this->normalizeTags($data['tags']);
@ -131,7 +130,6 @@ class TagBehavior extends Behavior
if (!$tag->isNew()) { if (!$tag->isNew()) {
continue; continue;
} }
$existingTag = $this->getExistingTag($tag->name); $existingTag = $this->getExistingTag($tag->name);
if (!$existingTag) { if (!$existingTag) {
continue; continue;
@ -176,15 +174,14 @@ class TagBehavior extends Behavior
$result[] = array_merge($common, ['id' => $existingTag->id]); $result[] = array_merge($common, ['id' => $existingTag->id]);
continue; continue;
} }
$result[] = array_merge( $result[] = array_merge(
$common, $common,
[ [
'name' => $tagIdentifier, 'name' => $tagIdentifier,
'colour' => '#924da6'
] ]
); );
} }
return $result; return $result;
} }

View File

@ -54,7 +54,6 @@ class AppController extends Controller
public function initialize(): void public function initialize(): void
{ {
parent::initialize(); parent::initialize();
$this->loadComponent('RequestHandler'); $this->loadComponent('RequestHandler');
$this->loadComponent('Flash'); $this->loadComponent('Flash');
$this->loadComponent('RestResponse'); $this->loadComponent('RestResponse');

View File

@ -64,8 +64,30 @@ class AuthKeysController extends AppController
public function add() public function add()
{ {
$this->set('metaGroup', $this->isAdmin ? 'Administration' : 'Cerebrate'); $this->set('metaGroup', $this->isAdmin ? 'Administration' : 'Cerebrate');
$validUsers = [];
$userConditions = [];
$currentUser = $this->ACL->getUser();
if (empty($currentUser['role']['perm_admin'])) {
if (empty($currentUser['role']['perm_org_admin'])) {
$userConditions['id'] = $currentUser['id'];
} else {
$role_ids = $this->Users->Roles->find()->where(['perm_admin' => 0])->all()->extract('id')->toList();
$userConditions['role_id IN'] = $role_ids;
}
}
$users = $this->Users->find('list');
if (!empty($userConditions)) {
$users->where($userConditions);
}
$users = $users->order(['username' => 'asc'])->all()->toList();
$this->CRUD->add([ $this->CRUD->add([
'displayOnSuccess' => 'authkey_display' 'displayOnSuccess' => 'authkey_display',
'beforeSave' => function($data) use ($users) {
if (!in_array($data['user_id'], array_keys($users))) {
return false;
}
return $data;
}
]); ]);
$responsePayload = $this->CRUD->getResponsePayload([ $responsePayload = $this->CRUD->getResponsePayload([
'displayOnSuccess' => 'authkey_display' 'displayOnSuccess' => 'authkey_display'
@ -75,9 +97,7 @@ class AuthKeysController extends AppController
} }
$this->loadModel('Users'); $this->loadModel('Users');
$dropdownData = [ $dropdownData = [
'user' => $this->Users->find('list', [ 'user' => $users
'sort' => ['username' => 'asc']
])
]; ];
$this->set(compact('dropdownData')); $this->set(compact('dropdownData'));
} }

View File

@ -68,6 +68,7 @@ class ACLComponent extends Component
'view' => ['perm_admin'] 'view' => ['perm_admin']
], ],
'EncryptionKeys' => [ 'EncryptionKeys' => [
'view' => ['*'],
'add' => ['*'], 'add' => ['*'],
'edit' => ['*'], 'edit' => ['*'],
'delete' => ['*'], 'delete' => ['*'],
@ -109,7 +110,7 @@ class ACLComponent extends Component
'batchAction' => ['perm_admin'], 'batchAction' => ['perm_admin'],
'broodTools' => ['perm_admin'], 'broodTools' => ['perm_admin'],
'connectionRequest' => ['perm_admin'], 'connectionRequest' => ['perm_admin'],
'connectLocal' => ['perm_admin'], // 'connectLocal' => ['perm_admin'],
'delete' => ['perm_admin'], 'delete' => ['perm_admin'],
'edit' => ['perm_admin'], 'edit' => ['perm_admin'],
'exposedTools' => ['OR' => ['perm_admin', 'perm_sync']], 'exposedTools' => ['OR' => ['perm_admin', 'perm_sync']],

View File

@ -175,6 +175,9 @@ class CRUDComponent extends Component
$data = $this->Table->patchEntity($data, $input, $patchEntityParams); $data = $this->Table->patchEntity($data, $input, $patchEntityParams);
if (isset($params['beforeSave'])) { if (isset($params['beforeSave'])) {
$data = $params['beforeSave']($data); $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); $savedData = $this->Table->save($data);
if ($savedData !== false) { if ($savedData !== false) {

View File

@ -39,7 +39,15 @@ class EncryptionKeysController extends AppController
public function delete($id) public function delete($id)
{ {
$this->CRUD->delete($id); $orgConditions = [];
$individualConditions = [];
$dropdownData = [];
$currentUser = $this->ACL->getUser();
$params = [];
if (empty($currentUser['role']['perm_admin'])) {
$params = $this->buildBeforeSave($params, $currentUser, $orgConditions, $individualConditions, $dropdownData);
}
$this->CRUD->delete($id, $params);
$responsePayload = $this->CRUD->getResponsePayload(); $responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) { if (!empty($responsePayload)) {
return $responsePayload; return $responsePayload;
@ -47,13 +55,8 @@ class EncryptionKeysController extends AppController
$this->set('metaGroup', 'ContactDB'); $this->set('metaGroup', 'ContactDB');
} }
public function add() private function buildBeforeSave(array $params, $currentUser, array &$orgConditions, array &$individualConditions, array &$dropdownData): array
{ {
$orgConditions = [];
$individualConditions = [];
$currentUser = $this->ACL->getUser();
$params = ['redirect' => $this->referer()];
if (empty($currentUser['role']['perm_admin'])) {
$orgConditions = [ $orgConditions = [
'id' => $currentUser['organisation_id'] 'id' => $currentUser['organisation_id']
]; ];
@ -84,12 +87,6 @@ class EncryptionKeysController extends AppController
} }
return $entity; return $entity;
}; };
}
$this->CRUD->add($params);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
$this->loadModel('Organisations'); $this->loadModel('Organisations');
$this->loadModel('Individuals'); $this->loadModel('Individuals');
$dropdownData = [ $dropdownData = [
@ -102,13 +99,35 @@ class EncryptionKeysController extends AppController
'conditions' => $individualConditions 'conditions' => $individualConditions
]) ])
]; ];
return $params;
}
public function add()
{
$orgConditions = [];
$individualConditions = [];
$dropdownData = [];
$currentUser = $this->ACL->getUser();
$params = [
'redirect' => $this->referer()
];
if (empty($currentUser['role']['perm_admin'])) {
$params = $this->buildBeforeSave($params, $currentUser, $orgConditions, $individualConditions, $dropdownData);
}
$this->CRUD->add($params);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
$this->set(compact('dropdownData')); $this->set(compact('dropdownData'));
$this->set('metaGroup', 'ContactDB'); $this->set('metaGroup', 'ContactDB');
} }
public function edit($id = false) public function edit($id = false)
{ {
$conditions = []; $orgConditions = [];
$individualConditions = [];
$dropdownData = [];
$currentUser = $this->ACL->getUser(); $currentUser = $this->ACL->getUser();
$params = [ $params = [
'fields' => [ 'fields' => [
@ -117,9 +136,7 @@ class EncryptionKeysController extends AppController
'redirect' => $this->referer() 'redirect' => $this->referer()
]; ];
if (empty($currentUser['role']['perm_admin'])) { if (empty($currentUser['role']['perm_admin'])) {
if (empty($currentUser['role']['perm_org_admin'])) { $params = $this->buildBeforeSave($params, $currentUser, $orgConditions, $individualConditions, $dropdownData);
}
} }
$this->CRUD->edit($id, $params); $this->CRUD->edit($id, $params);
$responsePayload = $this->CRUD->getResponsePayload(); $responsePayload = $this->CRUD->getResponsePayload();
@ -130,4 +147,16 @@ class EncryptionKeysController extends AppController
$this->set('metaGroup', 'ContactDB'); $this->set('metaGroup', 'ContactDB');
$this->render('add'); $this->render('add');
} }
public function view($id = false)
{
$this->CRUD->view($id, [
'contain' => ['Individuals', 'Organisations']
]);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
$this->set('metaGroup', 'ContactDB');
}
} }

View File

@ -70,6 +70,12 @@ class InstanceController extends AppController
usort($status, function($a, $b) { usort($status, function($a, $b) {
return strcmp($b['id'], $a['id']); 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('status', $status);
$this->set('updateAvailables', $migrationStatus['updateAvailables']); $this->set('updateAvailables', $migrationStatus['updateAvailables']);
} }
@ -140,6 +146,14 @@ class InstanceController extends AppController
{ {
$this->Settings = $this->getTableLocator()->get('Settings'); $this->Settings = $this->getTableLocator()->get('Settings');
$all = $this->Settings->getSettings(true); $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('settingsProvider', $all['settingsProvider']);
$this->set('settings', $all['settings']); $this->set('settings', $all['settings']);
$this->set('settingsFlattened', $all['settingsFlattened']); $this->set('settingsFlattened', $all['settingsFlattened']);

View File

@ -340,6 +340,7 @@ class LocalToolsController extends AppController
} }
} }
/*
public function connectLocal($local_tool_id) public function connectLocal($local_tool_id)
{ {
$params = [ $params = [
@ -355,10 +356,8 @@ class LocalToolsController extends AppController
$params['target_tool_id'] = $postParams['target_tool_id']; $params['target_tool_id'] = $postParams['target_tool_id'];
$result = $this->LocalTools->encodeLocalConnection($params); $result = $this->LocalTools->encodeLocalConnection($params);
// Send message to remote inbox // Send message to remote inbox
debug($result);
} else { } else {
$target_tools = $this->LocalTools->findConnectable($local_tool); $target_tools = $this->LocalTools->findConnectable($local_tool);
debug($target_tools);
if (empty($target_tools)) { if (empty($target_tools)) {
throw new NotFoundException(__('No tools found to connect.')); throw new NotFoundException(__('No tools found to connect.'));
} }
@ -369,4 +368,5 @@ class LocalToolsController extends AppController
]); ]);
} }
} }
*/
} }

View File

@ -9,6 +9,8 @@ use \Cake\Database\Expression\QueryExpression;
use Cake\Http\Exception\NotFoundException; use Cake\Http\Exception\NotFoundException;
use Cake\Http\Exception\MethodNotAllowedException; use Cake\Http\Exception\MethodNotAllowedException;
use Cake\Http\Exception\ForbiddenException; use Cake\Http\Exception\ForbiddenException;
use Cake\Http\Exception\UnauthorizedException;
class UserSettingsController extends AppController class UserSettingsController extends AppController
{ {
@ -19,8 +21,12 @@ class UserSettingsController extends AppController
public function index() public function index()
{ {
$conditions = []; $conditions = [];
$currentUser = $this->ACL->getUser();
if (empty($currentUser['role']['perm_admin'])) {
$conditions['user_id'] = $currentUser->id;
}
$this->CRUD->index([ $this->CRUD->index([
'conditions' => [], 'conditions' => $conditions,
'contain' => $this->containFields, 'contain' => $this->containFields,
'filters' => $this->filterFields, 'filters' => $this->filterFields,
'quickFilters' => $this->quickFilterFields, 'quickFilters' => $this->quickFilterFields,
@ -39,6 +45,9 @@ class UserSettingsController extends AppController
public function view($id) public function view($id)
{ {
if (!$this->isLoggedUserAllowedToEdit($id)) {
throw new NotFoundException(__('Invalid {0}.', 'user setting'));
}
$this->CRUD->view($id, [ $this->CRUD->view($id, [
'contain' => ['Users'] 'contain' => ['Users']
]); ]);
@ -50,10 +59,13 @@ class UserSettingsController extends AppController
public function add($user_id = false) public function add($user_id = false)
{ {
$currentUser = $this->ACL->getUser();
$this->CRUD->add([ $this->CRUD->add([
'redirect' => ['action' => 'index', $user_id], 'redirect' => ['action' => 'index', $user_id],
'beforeSave' => function($data) use ($user_id) { 'beforeSave' => function ($data) use ($currentUser) {
$data['user_id'] = $user_id; if (empty($currentUser['role']['perm_admin'])) {
$data['user_id'] = $currentUser->id;
}
return $data; return $data;
} }
]); ]);
@ -61,10 +73,13 @@ class UserSettingsController extends AppController
if (!empty($responsePayload)) { if (!empty($responsePayload)) {
return $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 = [ $dropdownData = [
'user' => $this->UserSettings->Users->find('list', [ 'user' => $allUsers->all()->toArray(),
'sort' => ['username' => 'asc']
]),
]; ];
$this->set(compact('dropdownData')); $this->set(compact('dropdownData'));
$this->set('user_id', $user_id); $this->set('user_id', $user_id);
@ -75,6 +90,11 @@ class UserSettingsController extends AppController
$entity = $this->UserSettings->find()->where([ $entity = $this->UserSettings->find()->where([
'id' => $id 'id' => $id
])->first(); ])->first();
if (!$this->isLoggedUserAllowedToEdit($entity)) {
throw new NotFoundException(__('Invalid {0}.', 'user setting'));
}
$entity = $this->CRUD->edit($id, [ $entity = $this->CRUD->edit($id, [
'redirect' => ['action' => 'index', $entity->user_id] 'redirect' => ['action' => 'index', $entity->user_id]
]); ]);
@ -94,6 +114,9 @@ class UserSettingsController extends AppController
public function delete($id) public function delete($id)
{ {
if (!$this->isLoggedUserAllowedToEdit($id)) {
throw new NotFoundException(__('Invalid {0}.', 'user setting'));
}
$this->CRUD->delete($id); $this->CRUD->delete($id);
$responsePayload = $this->CRUD->getResponsePayload(); $responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) { if (!empty($responsePayload)) {
@ -200,4 +223,29 @@ class UserSettingsController extends AppController
$this->set('user_id', $this->ACL->getUser()->id); $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

@ -97,8 +97,16 @@ class UsersController extends AppController
public function edit($id = false) public function edit($id = false)
{ {
$currentUser = $this->ACL->getUser(); $currentUser = $this->ACL->getUser();
if (empty($id) || (empty($currentUser['role']['perm_org_admin']) && empty($currentUser['role']['perm_site_admin']))) { if (empty($id)) {
$id = $currentUser['id']; $id = $currentUser['id'];
} else {
if ((empty($currentUser['role']['perm_org_admin']) && empty($currentUser['role']['perm_admin']))) {
if ($id !== $currentUser['id']) {
throw new MethodNotAllowedException(__('You are not authorised to edit that user.'));
} else {
$id = $currentUser['id'];
}
}
} }
$params = [ $params = [
@ -111,12 +119,15 @@ class UsersController extends AppController
'password' 'password'
], ],
'fields' => [ 'fields' => [
'id', 'individual_id', 'username', 'disabled', 'password', 'confirm_password' 'password', 'confirm_password'
] ]
]; ];
if (!empty($this->ACL->getUser()['role']['perm_admin'])) { if (!empty($this->ACL->getUser()['role']['perm_admin'])) {
$params['fields'][] = 'individual_id';
$params['fields'][] = 'username';
$params['fields'][] = 'role_id'; $params['fields'][] = 'role_id';
$params['fields'][] = 'organisation_id'; $params['fields'][] = 'organisation_id';
$params['fields'][] = 'disabled';
} }
$this->CRUD->edit($id, $params); $this->CRUD->edit($id, $params);
$responsePayload = $this->CRUD->getResponsePayload(); $responsePayload = $this->CRUD->getResponsePayload();

View File

@ -2,6 +2,8 @@
namespace CommonConnectorTools; namespace CommonConnectorTools;
use Cake\ORM\Locator\LocatorAwareTrait; use Cake\ORM\Locator\LocatorAwareTrait;
use Cake\Log\Log;
use Cake\Log\Engine\FileLog;
class CommonConnectorTools class CommonConnectorTools
{ {
@ -20,6 +22,35 @@ class CommonConnectorTools
const STATE_CANCELLED = 'Request cancelled'; const STATE_CANCELLED = 'Request cancelled';
const STATE_DECLINED = 'Request declined by remote'; const STATE_DECLINED = 'Request declined by remote';
public function __construct()
{
Log::setConfig("LocalToolDebug", [
'className' => FileLog::class,
'path' => LOGS,
'file' => "{$this->connectorName}-debug",
'scopes' => [$this->connectorName],
'levels' => ['notice', 'info', 'debug'],
]);
Log::setConfig("LocalToolError", [
'className' => FileLog::class,
'path' => LOGS,
'file' => "{$this->connectorName}-error",
'scopes' => [$this->connectorName],
'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
]);
}
protected function logDebug($message)
{
Log::debug($message, [$this->connectorName]);
}
protected function logError($message, $scope=[])
{
Log::error($message, [$this->connectorName]);
}
public function addExposedFunction(string $functionName): void public function addExposedFunction(string $functionName): void
{ {
$this->exposedFunctions[] = $functionName; $this->exposedFunctions[] = $functionName;

View File

@ -122,6 +122,11 @@ class MispConnector extends CommonConnectorTools
'type' => 'boolean' 'type' => 'boolean'
], ],
]; ];
public $settingsPlaceholder = [
'url' => 'https://your.misp.intance',
'authkey' => '',
'skip_ssl' => '0',
];
public function addSettingValidatorRules($validator) public function addSettingValidatorRules($validator)
{ {
@ -183,6 +188,7 @@ class MispConnector extends CommonConnectorTools
$settings = json_decode($connection->settings, true); $settings = json_decode($connection->settings, true);
$http = $this->genHTTPClient($connection, $options); $http = $this->genHTTPClient($connection, $options);
$url = sprintf('%s%s', $settings['url'], $relativeURL); $url = sprintf('%s%s', $settings['url'], $relativeURL);
$this->logDebug(sprintf('%s %s %s', __('Posting data') . PHP_EOL, "POST {$url}" . PHP_EOL, json_encode($data)));
return $http->post($url, $data, $options); return $http->post($url, $data, $options);
} }
@ -234,14 +240,18 @@ class MispConnector extends CommonConnectorTools
if (!empty($params['softError'])) { if (!empty($params['softError'])) {
return $response; return $response;
} }
throw new NotFoundException(__('Could not retrieve the requested resource.')); $errorMsg = __('Could not post to the requested resource for `{0}`. Remote returned:', $url) . PHP_EOL . $response->getStringBody();
$this->logError($errorMsg);
throw new NotFoundException($errorMsg);
} }
} }
private function postData(string $url, array $params): Response private function postData(string $url, array $params): Response
{ {
if (empty($params['connection'])) { if (empty($params['connection'])) {
throw new NotFoundException(__('No connection object received.')); $errorMsg = __('No connection object received.');
$this->logError($errorMsg);
throw new NotFoundException($errorMsg);
} }
$url = $this->urlAppendParams($url, $params); $url = $this->urlAppendParams($url, $params);
if (!is_string($params['body'])) { if (!is_string($params['body'])) {
@ -251,7 +261,9 @@ class MispConnector extends CommonConnectorTools
if ($response->isOk()) { if ($response->isOk()) {
return $response; return $response;
} else { } else {
throw new NotFoundException(__('Could not post to the requested resource. Remote returned:') . PHP_EOL . $response->getStringBody()); $errorMsg = __('Could not post to the requested resource for `{0}`. Remote returned:', $url) . PHP_EOL . $response->getStringBody();
$this->logError($errorMsg);
throw new NotFoundException($errorMsg);
} }
} }

View File

@ -46,6 +46,22 @@ class SkeletonConnector extends CommonConnectorTools
'redirect' => 'serverSettingsAction' '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 public function health(Object $connection): array
{ {

View File

@ -0,0 +1,11 @@
<?php
namespace App\Model\Entity;
use App\Model\Entity\AppModel;
use Cake\ORM\Entity;
class Outbox extends AppModel
{
}

View File

@ -143,7 +143,8 @@ class LocalToolsTable extends AppTable
'connector' => $connector_type, 'connector' => $connector_type,
'connector_version' => $connector_class->version, 'connector_version' => $connector_class->version,
'connector_description' => $connector_class->description, 'connector_description' => $connector_class->description,
'connector_settings' => $connector_class->settings ?? [] 'connector_settings' => $connector_class->settings ?? [],
'connector_settings_placeholder' => $connector_class->settingsPlaceholder ?? [],
]; ];
if ($includeConnections) { if ($includeConnections) {
$connector['connections'] = $this->healthCheck($connector_type, $connector_class); $connector['connections'] = $this->healthCheck($connector_type, $connector_class);
@ -288,6 +289,7 @@ class LocalToolsTable extends AppTable
return $jsonReply; return $jsonReply;
} }
/*
public function findConnectable($local_tool): array public function findConnectable($local_tool): array
{ {
$connectors = $this->getInterconnectors($local_tool['connector']); $connectors = $this->getInterconnectors($local_tool['connector']);
@ -297,8 +299,8 @@ class LocalToolsTable extends AppTable
$validTargets[$connector['connects'][1]] = 1; $validTargets[$connector['connects'][1]] = 1;
} }
} }
} }
*/
public function fetchConnection($id): object public function fetchConnection($id): object
{ {

View File

@ -11,7 +11,7 @@ use App\Settings\SettingsProvider\UserSettingsProvider;
class UserSettingsTable extends AppTable class UserSettingsTable extends AppTable
{ {
protected $BOOKMARK_SETTING_NAME = 'ui.bookmarks'; public $BOOKMARK_SETTING_NAME = 'ui.bookmarks';
public function initialize(array $config): void public function initialize(array $config): void
{ {

View File

@ -637,13 +637,13 @@ class BoostrapTable extends BootstrapGeneric {
], ],
]); ]);
foreach ($this->items as $i => $row) { foreach ($this->items as $i => $row) {
$body .= $this->genRow($row); $body .= $this->genRow($row, $i);
} }
$body .= $this->closeNode('tbody'); $body .= $this->closeNode('tbody');
return $body; return $body;
} }
private function genRow($row) private function genRow($row, $rowIndex)
{ {
$html = $this->openNode('tr',[ $html = $this->openNode('tr',[
'class' => [ 'class' => [
@ -658,21 +658,21 @@ class BoostrapTable extends BootstrapGeneric {
$key = $field; $key = $field;
} }
$cellValue = Hash::get($row, $key); $cellValue = Hash::get($row, $key);
$html .= $this->genCell($cellValue, $field, $row, $i); $html .= $this->genCell($cellValue, $field, $row, $rowIndex);
} }
} else { // indexed array } else { // indexed array
foreach ($row as $cellValue) { foreach ($row as $i => $cellValue) {
$html .= $this->genCell($cellValue, $field, $row, $i); $html .= $this->genCell($cellValue, 'index', $row, $rowIndex);
} }
} }
$html .= $this->closeNode('tr'); $html .= $this->closeNode('tr');
return $html; return $html;
} }
private function genCell($value, $field=[], $row=[], $i=0) private function genCell($value, $field=[], $row=[], $rowIndex=0)
{ {
if (isset($field['formatter'])) { if (isset($field['formatter'])) {
$cellContent = $field['formatter']($value, $row, $i); $cellContent = $field['formatter']($value, $row, $rowIndex);
} else if (isset($field['element'])) { } else if (isset($field['element'])) {
$cellContent = $this->btHelper->getView()->element($field['element'], [ $cellContent = $this->btHelper->getView()->element($field['element'], [
'data' => [$value], 'data' => [$value],

View File

@ -0,0 +1,32 @@
<?php
echo $this->element(
'/genericElements/SingleViews/single_view',
[
'data' => $entity,
'fields' => [
[
'key' => __('ID'),
'path' => 'id'
],
[
'key' => __('Type'),
'path' => 'type'
],
[
'key' => __('Owner'),
'path' => 'owner_id',
'owner_model_path' => 'owner_model',
'type' => 'owner'
],
[
'key' => __('Revoked'),
'path' => 'revoked'
],
[
'key' => __('Key'),
'path' => 'encryption_key'
]
]
]
);

View File

@ -23,7 +23,8 @@
), ),
array( array(
'field' => 'tag_list', 'field' => 'tag_list',
'type' => 'tags' 'type' => 'tags',
'requirements' => $this->request->getParam('action') === 'edit'
), ),
), ),
'metaTemplates' => empty($metaTemplates) ? [] : $metaTemplates, 'metaTemplates' => empty($metaTemplates) ? [] : $metaTemplates,

View File

@ -22,7 +22,8 @@
'codemirror' => [ 'codemirror' => [
'height' => '10rem', 'height' => '10rem',
'hints' => $connectors[0]['connector_settings'] 'hints' => $connectors[0]['connector_settings']
] ],
'placeholder' => json_encode($connectors[0]['connector_settings_placeholder'], JSON_FORCE_OBJECT | JSON_PRETTY_PRINT)
], ],
[ [
'field' => 'description', 'field' => 'description',

View File

@ -89,12 +89,14 @@ echo $this->element('genericElements/IndexTable/index_table', [
'url_params_data_paths' => ['id'], 'url_params_data_paths' => ['id'],
'icon' => 'eye' 'icon' => 'eye'
], ],
/*
[ [
'open_modal' => '/localTools/connectLocal/[onclick_params_data_path]', 'open_modal' => '/localTools/connectLocal/[onclick_params_data_path]',
'modal_params_data_path' => 'id', 'modal_params_data_path' => 'id',
'reload_url' => sprintf('/localTools/connectorIndex/%s', h($connectorName)), 'reload_url' => sprintf('/localTools/connectorIndex/%s', h($connectorName)),
'icon' => 'plug' 'icon' => 'plug'
], ],
*/
[ [
'open_modal' => '/localTools/edit/[onclick_params_data_path]', 'open_modal' => '/localTools/edit/[onclick_params_data_path]',
'modal_params_data_path' => 'id', 'modal_params_data_path' => 'id',

View File

@ -7,17 +7,13 @@
array( array(
'field' => 'name' 'field' => 'name'
), ),
array(
'field' => 'description',
'type' => 'textarea'
),
array( array(
'field' => 'uuid', 'field' => 'uuid',
'label' => 'UUID', 'label' => 'UUID',
'type' => 'uuid' 'type' => 'uuid'
), ),
array( array(
'field' => 'URL' 'field' => 'url'
), ),
array( array(
'field' => 'nationality' 'field' => 'nationality'

View File

@ -0,0 +1,6 @@
<?php
echo $this->element('/genericElements/IndexTable/Fields/owner', [
'field' => $field,
'row' => $data
]);
?>

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/lint/json-lint') ?>
<?= $this->Html->script('CodeMirror/addon/edit/matchbrackets') ?> <?= $this->Html->script('CodeMirror/addon/edit/matchbrackets') ?>
<?= $this->Html->script('CodeMirror/addon/edit/closebrackets') ?> <?= $this->Html->script('CodeMirror/addon/edit/closebrackets') ?>
<?= $this->Html->script('CodeMirror/addon/display/placeholder') ?>
<?= $this->Html->css('CodeMirror/codemirror') ?> <?= $this->Html->css('CodeMirror/codemirror') ?>
<?= $this->Html->css('CodeMirror/codemirror-additional') ?> <?= $this->Html->css('CodeMirror/codemirror-additional') ?>
<?= $this->Html->css('CodeMirror/addon/hint/show-hint') ?> <?= $this->Html->css('CodeMirror/addon/hint/show-hint') ?>

View File

@ -27,3 +27,7 @@
.CodeMirror-hints { .CodeMirror-hints {
z-index: 1060 !important; /* Make sure hint is above modal */ 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) === "");
}
});