Merge branch 'develop' into main

feature/docker-ci v0.3
iglocska 2021-06-30 17:06:29 +02:00
commit efbf5f0d2c
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
8 changed files with 214 additions and 16 deletions

View File

@ -98,7 +98,7 @@ class ACLComponent extends Component
'connectLocal' => ['perm_admin'], 'connectLocal' => ['perm_admin'],
'delete' => ['perm_admin'], 'delete' => ['perm_admin'],
'edit' => ['perm_admin'], 'edit' => ['perm_admin'],
'exposedTools' => ['perm_admin'], 'exposedTools' => ['OR' => ['perm_admin', 'perm_sync']],
'index' => ['perm_admin'], 'index' => ['perm_admin'],
'connectorIndex' => ['perm_admin'], 'connectorIndex' => ['perm_admin'],
'view' => ['perm_admin'], 'view' => ['perm_admin'],

View File

@ -165,7 +165,8 @@ class CRUDComponent extends Component
} }
} else { } else {
$this->Controller->isFailResponse = true; $this->Controller->isFailResponse = true;
$validationMessage = $this->prepareValidationError($data); $validationErrors = $data->getErrors();
$validationMessage = $this->prepareValidationMessage($validationErrors);
$message = __( $message = __(
'{0} could not be added.{1}', '{0} could not be added.{1}',
$this->ObjectAlias, $this->ObjectAlias,
@ -174,7 +175,7 @@ class CRUDComponent extends Component
if ($this->Controller->ParamHandler->isRest()) { if ($this->Controller->ParamHandler->isRest()) {
$this->Controller->restResponsePayload = $this->RestResponse->viewData($message, 'json'); $this->Controller->restResponsePayload = $this->RestResponse->viewData($message, 'json');
} else if ($this->Controller->ParamHandler->isAjax()) { } else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'add', $data, $message, $validationMessage); $this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'add', $data, $message, $validationErrors);
} else { } else {
$this->Controller->Flash->error($message); $this->Controller->Flash->error($message);
} }
@ -183,6 +184,21 @@ class CRUDComponent extends Component
$this->Controller->set('entity', $data); $this->Controller->set('entity', $data);
} }
private function prepareValidationMessage($errors)
{
$validationMessage = '';
if (!empty($errors)) {
if (count($errors) == 1) {
$field = array_keys($errors)[0];
$fieldError = implode(', ', array_values($errors[$field]));
$validationMessage = __('{0}: {1}', $field, $fieldError);
} else {
$validationMessage = __('There has been validation issues with multiple fields');
}
}
return $validationMessage;
}
private function prepareValidationError($data) private function prepareValidationError($data)
{ {
$validationMessage = ''; $validationMessage = '';
@ -192,7 +208,7 @@ class CRUDComponent extends Component
foreach ($errorData as $key => $value) { foreach ($errorData as $key => $value) {
$errorMessages[] = $value; $errorMessages[] = $value;
} }
$validationMessage .= __(' {1}', $field, implode(',', $errorMessages)); $validationMessage .= __('{0}: {1}', $field, implode(',', $errorMessages));
} }
} }
return $validationMessage; return $validationMessage;
@ -261,14 +277,15 @@ class CRUDComponent extends Component
} }
} }
} else { } else {
$validationMessage = $this->prepareValidationError($data); $validationErrors = $data->getErrors();
$validationMessage = $this->prepareValidationMessage($validationErrors);
$message = __( $message = __(
__('{0} could not be modified.'), __('{0} could not be modified.'),
$this->ObjectAlias $this->ObjectAlias
); );
if ($this->Controller->ParamHandler->isRest()) { if ($this->Controller->ParamHandler->isRest()) {
} else if ($this->Controller->ParamHandler->isAjax()) { } else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', $data, $message, $data->getErrors()); $this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'edit', $data, $message, $validationErrors);
} else { } else {
$this->Controller->Flash->error($message); $this->Controller->Flash->error($message);
} }
@ -699,7 +716,8 @@ class CRUDComponent extends Component
} }
} }
} else { } else {
$validationMessage = $this->prepareValidationError($data); $validationErrors = $data->getErrors();
$validationMessage = $this->prepareValidationMessage($validationErrors);
$message = __( $message = __(
'{0} could not be modified.{1}', '{0} could not be modified.{1}',
$this->ObjectAlias, $this->ObjectAlias,
@ -707,7 +725,7 @@ class CRUDComponent extends Component
); );
if ($this->Controller->ParamHandler->isRest()) { if ($this->Controller->ParamHandler->isRest()) {
} else if ($this->Controller->ParamHandler->isAjax()) { } else if ($this->Controller->ParamHandler->isAjax()) {
$this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'toggle', $message, $validationMessage); $this->Controller->ajaxResponsePayload = $this->RestResponse->ajaxFailResponse($this->ObjectAlias, 'toggle', $message, $validationErrors);
} else { } else {
$this->Controller->Flash->error($message); $this->Controller->Flash->error($message);
if (empty($params['redirect'])) { if (empty($params['redirect'])) {

View File

@ -0,0 +1,171 @@
<?php
// set a namespace for the module
namespace SkeletonConnector;
// These can be left as is. We want to have access to the commonconnector tools as well as basic http / exception functions
require_once(ROOT . '/src/Lib/default/local_tool_connectors/CommonConnectorTools.php');
use CommonConnectorTools\CommonConnectorTools;
use Cake\Http\Client;
use Cake\Http\Exception\NotFoundException;
use Cake\Http\Exception\MethodNotAllowedException;
use Cake\Http\Client\Response;
class SkeletonConnector extends CommonConnectorTools
{
/*
*
* ====================================== Metainformation block ======================================
*
*/
public $description = '';
public $connectorName = 'SkeletonConnector';
public $name = 'Skeleton';
public $version = '0.1';
// exposed function list and configuration
public $exposedFunctions = [
'myIndexAction' => [
'type' => 'index',
'scope' => 'child',
'params' => [
'quickFilter',
'sort',
'direction',
'page',
'limit'
]
],
'myFormAction' => [
'type' => 'formAction',
'scope' => 'childAction',
'params' => [
'setting',
'value'
],
'redirect' => 'serverSettingsAction'
]
];
public function health(Object $connection): array
{
/*
returns an array with 2 keys:
[
status: the numeric response code (0: UNKNOWN, 1: OK, 2: ISSUES, 3: ERROR),
message: status message shown
]
*/
return $health;
}
/*
*
* ====================================== Exposed custom functions ======================================
*
*/
public function myIndexAction(array $params): array
{
// $data = get data from local tool
//if we want to filter it via the quicksearch
if (!empty($params['quickFilter'])) {
// filter $data
}
// return the data embedded in a generic index parameter array
return [
'type' => 'index',
'title' => false,
'description' => false,
'data' => [
'data' => $data,
'skip_pagination' => 1,
'top_bar' => [
'children' => [
[
'type' => 'search',
'button' => __('Filter'),
'placeholder' => __('Enter value to search'),
'data' => '',
'searchKey' => 'value',
'additionalUrlParams' => $urlParams
]
]
],
'fields' => [
[
'name' => 'field1_name',
'sort' => 'field1.path',
'data_path' => 'field1.path',
]
],
'pull' => 'right',
'actions' => [
[
'open_modal' => '/localTools/action/' . h($params['connection']['id']) . '/myForm?myKey={{0}}',
'modal_params_data_path' => ['myKey'],
'icon' => 'font_awesome_icon_name',
'reload_url' => '/localTools/action/' . h($params['connection']['id']) . '/myIndex'
]
]
]
];
}
public function myFormAction(array $params): array
{
if ($params['request']->is(['get'])) {
return [
'data' => [
'title' => __('My Form Title'),
'description' => __('My form description'),
'submit' => [
'action' => $params['request']->getParam('action')
],
'url' => ['controller' => 'localTools', 'action' => 'action', h($params['connection']['id']), 'myFormAction']
]
];
} elseif ($params['request']->is(['post'])) {
// handle posted data
if ($success) {
return ['success' => 1, 'message' => __('Action successful.')];
} else {
return ['success' => 0, 'message' => __('Action failed spectacularly.')];
}
}
throw new MethodNotAllowedException(__('Invalid http request type for the given action.'));
}
/*
*
* ====================================== Inter connection functions ======================================
*
*/
public function initiateConnection(array $params): array
{
// encode initial connection in local tool
// build and return initiation payload
return $payload;
}
public function acceptConnection(array $params): array
{
// encode acceptance of the connection request in local tool, based on the payload from the initiation
// return payload for remote to encode the connection
return $payload;
}
public function finaliseConnection(array $params): bool
{
// based on the payload from the acceptance, finalise the connection
// return true on success
return $success;
}
}
?>

View File

@ -26,7 +26,12 @@ class BroodsTable extends AppTable
public function validationDefault(Validator $validator): Validator public function validationDefault(Validator $validator): Validator
{ {
return $validator; return $validator
->requirePresence(['name', 'url', 'organisation_id'], 'create')
->notEmptyString('name')
->notEmptyString('url')
->url('url', __('The provided value is not a valid URL'))
->naturalNumber('organisation_id', false);
} }
public function genHTTPClient(Object $brood, array $options=[]): Object public function genHTTPClient(Object $brood, array $options=[]): Object

View File

@ -26,7 +26,8 @@
'field' => 'organisation_id', 'field' => 'organisation_id',
'label' => __('Owner organisation'), 'label' => __('Owner organisation'),
'options' => $dropdownData['organisation'], 'options' => $dropdownData['organisation'],
'type' => 'dropdown' 'type' => 'dropdown',
'empty' => __('-- pick one --')
), ),
array( array(
'field' => 'trusted', 'field' => 'trusted',

View File

@ -1,6 +1,7 @@
<?php <?php
$controlParams = [ $controlParams = [
'options' => $fieldData['options'], 'options' => $fieldData['options'],
'empty' => $fieldData['empty'] ?? false,
'class' => ($fieldData['class'] ?? '') . ' formDropdown custom-select' 'class' => ($fieldData['class'] ?? '') . ' formDropdown custom-select'
]; ];
echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData); echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData);

View File

@ -107,7 +107,7 @@
.click(function() { .click(function() {
const url = `/${controller}/filtering` const url = `/${controller}/filtering`
const reloadUrl = `/${controller}/index${additionalUrlParams}` const reloadUrl = `/${controller}/index${additionalUrlParams}`
openFilteringModal(this, url, reloadUrl, $(`#table-container-${randomValue}`)); openFilteringModal(this, url, reloadUrl, $(`#index-table-${randomValue}`));
}) })
function doFilter($button) { function doFilter($button) {
@ -151,7 +151,8 @@
} }
function openFilteringModal(clicked, url, reloadUrl, tableId) { function openFilteringModal(clicked, url, reloadUrl, tableId) {
UI.overlayUntilResolve(clicked, UI.submissionModalForIndex(url, reloadUrl, tableId)) const modalPromise = UI.submissionModalForIndex(url, reloadUrl, tableId)
UI.overlayUntilResolve(clicked, modalPromise)
} }
}); });
</script> </script>

View File

@ -996,21 +996,22 @@ class FormValidationHelper {
injectValidationErrorInForm(fieldName, errors) { injectValidationErrorInForm(fieldName, errors) {
const inputField = Array.from(this.form).find(node => { return node.name == fieldName }) const inputField = Array.from(this.form).find(node => { return node.name == fieldName })
if (inputField !== undefined) { if (inputField !== undefined) {
const $messageNode = this.buildValidationMessageNode(errors) const $messageNode = this.buildValidationMessageNode(fieldName, errors)
const $inputField = $(inputField) const $inputField = $(inputField)
$inputField.addClass('is-invalid') $inputField.addClass('is-invalid')
$messageNode.insertAfter($inputField) $messageNode.insertAfter($inputField)
} else { } else {
const $messageNode = this.buildValidationMessageNode(errors, true) const $messageNode = this.buildValidationMessageNode(fieldName, errors, true)
const $flashContainer = $(this.form).parent().find('#flashContainer') const $flashContainer = $(this.form).parent().find('#flashContainer')
$messageNode.insertAfter($flashContainer) $messageNode.insertAfter($flashContainer)
} }
} }
buildValidationMessageNode(errors, isAlert=false) { buildValidationMessageNode(fieldName, errors, isAlert=false) {
const $messageNode = $('<div></div>') const $messageNode = $('<div></div>')
if (isAlert) { if (isAlert) {
$messageNode.addClass('alert alert-danger').attr('role', 'alert') $messageNode.addClass('alert alert-danger').attr('role', 'alert')
$messageNode.append($('<strong></strong>').text(`${fieldName}: `))
} else { } else {
$messageNode.addClass('invalid-feedback') $messageNode.addClass('invalid-feedback')
} }
@ -1020,7 +1021,7 @@ class FormValidationHelper {
if (hasMultipleErrors) { if (hasMultipleErrors) {
$messageNode.append($('<li></li>').text(error)) $messageNode.append($('<li></li>').text(error))
} else { } else {
$messageNode.text(error) $messageNode.append($('<span></span>').text(error))
} }
} }
} else { } else {