diff --git a/libraries/default/RequestProcessors/BroodRequestProcessor.php b/libraries/default/RequestProcessors/BroodRequestProcessor.php
new file mode 100644
index 0000000..13a0c33
--- /dev/null
+++ b/libraries/default/RequestProcessors/BroodRequestProcessor.php
@@ -0,0 +1,108 @@
+description = __('Handle tool interconnection request from other cerebrate instance');
+ $this->Broods = TableRegistry::getTableLocator()->get('Broods');
+ }
+
+ protected function addValidatorRules($validator)
+ {
+ return $validator;
+ }
+
+ public function create($requestData) {
+ $this->validateRequestData($requestData);
+ $requestData['title'] = __('Cerebrate instance {0} requested interconnection for tool {1}', 'Insert brood name', 'Insert tool name');
+ return parent::create($requestData);
+ }
+
+ public function process($id, $requestData)
+ {
+ $connectionSuccessfull = false;
+ $interConnectionResult = [];
+ if ($connectionSuccessfull) {
+ $this->discard($id, $requestData);
+ }
+ return $this->genActionResult(
+ $interConnectionResult,
+ $connectionSuccessfull,
+ $connectionSuccessfull ? __('Interconnection for `{0}` created', 'Insert tool name') : __('Could interconnect tool `{0}`.', 'Insert tool name'),
+ []
+ );
+ }
+
+ public function discard($id, $requestData)
+ {
+ return parent::discard($id, $requestData);
+ }
+}
+
+class OneWaySynchronizationProcessor extends BroodRequestProcessor implements GenericProcessorActionI {
+ public $action = 'OneWaySynchronization';
+ protected $description;
+
+ public function __construct() {
+ parent::__construct();
+ $this->description = __('Handle cerebrate connection request for another cerebrate instance');
+ $this->Broods = TableRegistry::getTableLocator()->get('Broods');
+ }
+
+ protected function addValidatorRules($validator)
+ {
+ return $validator;
+ }
+
+ public function create($requestData) {
+ $this->validateRequestData($requestData);
+ $requestData['title'] = __('Cerebrate instance {0} requested interconnection', 'Insert cerebrate name');
+ return parent::create($requestData);
+ }
+
+ public function process($id, $requestData)
+ {
+ $connectionSuccessfull = false;
+ $interConnectionResult = [];
+ if ($connectionSuccessfull) {
+ $this->discard($id, $requestData);
+ }
+ return $this->genActionResult(
+ $interConnectionResult,
+ $connectionSuccessfull,
+ $connectionSuccessfull ? __('Interconnection with `{0}` created', 'Insert cerebrate name') : __('Could interconnect with `{0}`.', 'Insert cerebrate name'),
+ []
+ );
+ }
+
+ public function discard($id, $requestData)
+ {
+ return parent::discard($id, $requestData);
+ }
+}
\ No newline at end of file
diff --git a/libraries/default/RequestProcessors/GenericRequestProcessor.php b/libraries/default/RequestProcessors/GenericRequestProcessor.php
new file mode 100644
index 0000000..b5d2300
--- /dev/null
+++ b/libraries/default/RequestProcessors/GenericRequestProcessor.php
@@ -0,0 +1,202 @@
+Inbox = TableRegistry::getTableLocator()->get('Inbox');
+ if ($registerActions) {
+ $this->registerActionInProcessor();
+ }
+ $processingTemplatePath = $this->getProcessingTemplatePath();
+ $file = new File($this->processingTemplatesDirectory . DS . $processingTemplatePath);
+ if ($file->exists()) {
+ $this->processingTemplate = str_replace('.php', '', $processingTemplatePath);
+ }
+ $file->close();
+ }
+
+ public function getRegisteredActions()
+ {
+ return $this->registeredActions;
+ }
+ public function getScope()
+ {
+ return $this->scope;
+ }
+
+ private function getProcessingTemplatePath()
+ {
+ $class = str_replace('RequestProcessor', '', get_parent_class($this));
+ $action = strtolower(str_replace('Processor', '', get_class($this)));
+ return sprintf('%s/%s.php',
+ $class,
+ $action
+ );
+ }
+
+ public function getProcessingTemplate()
+ {
+ return $this->processingTemplate;
+ }
+
+ public function render($request=[])
+ {
+ $processingTemplate = $this->getProcessingTemplate();
+ $viewVariables = $this->getViewVariables($request);
+ $builder = new ViewBuilder();
+ $builder->disableAutoLayout()
+ ->setClassName('Monad')
+ ->setTemplate($processingTemplate);
+ $view = $builder->build($viewVariables);
+ return $view->render();
+ }
+
+ protected function generateRequest($requestData)
+ {
+ $request = $this->Inbox->newEmptyEntity();
+ $request = $this->Inbox->patchEntity($request, $requestData);
+ if ($request->getErrors()) {
+ throw new Exception(__('Could not create request.{0}Reason: {1}', PHP_EOL, json_encode($request->getErrors())), 1);
+ }
+ return $request;
+ }
+
+ protected function validateRequestData($requestData)
+ {
+ $errors = [];
+ if (!isset($requestData['data'])) {
+ $errors[] = __('No request data provided');
+ }
+ $validator = new Validator();
+ if (method_exists($this, 'addValidatorRules')) {
+ $validator = $this->addValidatorRules($validator);
+ $errors = $validator->validate($requestData['data']);
+ }
+ if (!empty($errors)) {
+ throw new Exception('Error while validating request data. ' . json_encode($errors), 1);
+ }
+ }
+
+ protected function registerActionInProcessor()
+ {
+ foreach ($this->registeredActions as $i => $action) {
+ $className = "{$action}Processor";
+ $reflection = new ReflectionClass($className);
+ if ($reflection->isAbstract() || $reflection->isInterface()) {
+ throw new Exception(__('Cannot create instance of %s, as it is abstract or is an interface'));
+ }
+ $this->{$action} = $reflection->newInstance();
+ }
+ }
+
+ protected function getViewVariablesConfirmModal($id, $title='', $question='', $actionName='')
+ {
+ return [
+ 'title' => !empty($title) ? $title : __('Process request {0}', $id),
+ 'question' => !empty($question) ? $question : __('Confirm request {0}', $id),
+ 'actionName' => !empty($actionName) ? $actionName : __('Confirm'),
+ 'path' => ['controller' => 'inbox', 'action' => 'process', $id]
+ ];
+ }
+
+ public function getViewVariables($request)
+ {
+ return $this->getViewVariablesConfirmModal($request->id, '', '', '');
+ }
+
+ protected function genActionResult($data, $success, $message, $errors=[])
+ {
+ return [
+ 'data' => $data,
+ 'success' => $success,
+ 'message' => $message,
+ 'errors' => $errors,
+ ];
+ }
+
+ public function genHTTPReply($controller, $processResult, $redirect=null)
+ {
+ $scope = $this->scope;
+ $action = $this->action;
+ if ($processResult['success']) {
+ $message = !empty($processResult['message']) ? $processResult['message'] : __('Request {0} successfully processed.', $id);
+ if ($controller->ParamHandler->isRest()) {
+ $response = $controller->RestResponse->viewData($processResult, 'json');
+ } else if ($controller->ParamHandler->isAjax()) {
+ $response = $controller->RestResponse->ajaxSuccessResponse('RequestProcessor', "{$scope}.{$action}", $processResult['data'], $message);
+ } else {
+ $controller->Flash->success($message);
+ if (!is_null($redirect)) {
+ $response = $controller->redirect($redirect);
+ } else {
+ $response = $controller->redirect(['action' => 'index']);
+ }
+ }
+ } else {
+ $message = !empty($processResult['message']) ? $processResult['message'] : __('Request {0} could not be processed.', $id);
+ if ($controller->ParamHandler->isRest()) {
+ $response = $controller->RestResponse->viewData($processResult, 'json');
+ } else if ($controller->ParamHandler->isAjax()) {
+ $response = $controller->RestResponse->ajaxFailResponse('RequestProcessor', "{$scope}.{$action}", $processResult['data'], $message, $processResult['errors']);
+ } else {
+ $controller->Flash->error($message);
+ if (!is_null($redirect)) {
+ $response = $controller->redirect($redirect);
+ } else {
+ $response = $controller->redirect(['action' => 'index']);
+ }
+ }
+ }
+
+ return $response;
+ }
+
+ public function checkLoading()
+ {
+ return 'Assimilation successful!';
+ }
+
+ public function create($requestData)
+ {
+ $requestData['scope'] = $this->scope;
+ $requestData['action'] = $this->action;
+ $requestData['description'] = $this->description;
+ $request = $this->generateRequest($requestData);
+ $savedRequest = $this->Inbox->save($request);
+ return $this->genActionResult(
+ $savedRequest,
+ $savedRequest !== false,
+ __('{0} request for {1} created', $this->scope, $this->action),
+ $request->getErrors()
+ );
+ }
+
+ public function discard($id, $requestData)
+ {
+ $request = $this->Inbox->get($id);
+ $this->Inbox->delete($request);
+ return $this->genActionResult(
+ [],
+ true,
+ __('{0}.{1} request #{2} discarded', $this->scope, $this->action, $id)
+ );
+ }
+}
diff --git a/libraries/default/RequestProcessors/ProposalRequestProcessor.php b/libraries/default/RequestProcessors/ProposalRequestProcessor.php
new file mode 100644
index 0000000..3421edf
--- /dev/null
+++ b/libraries/default/RequestProcessors/ProposalRequestProcessor.php
@@ -0,0 +1,65 @@
+description = __('Handle proposal from users for this cerebrate instance');
+ $this->Users = TableRegistry::getTableLocator()->get('Users');
+ }
+
+ protected function addValidatorRules($validator)
+ {
+ return $validator;
+ }
+
+ public function create($requestData) {
+ $this->validateRequestData($requestData);
+ $requestData['title'] = __('User `{0}` would like to modify record `{0}`', 'username', 'recordname');
+ return parent::create($requestData);
+ }
+
+ public function process($id, $requestData)
+ {
+ $proposalAccepted = false;
+ $saveResult = [];
+ if ($proposalAccepted) {
+ $this->discard($id, $requestData);
+ }
+ return $this->genActionResult(
+ $saveResult,
+ $proposalAccepted,
+ $proposalAccepted ? __('Record `{0}` modify', 'recordname') : __('Could modify record `{0}`.', 'recordname'),
+ []
+ );
+ }
+
+ public function discard($id, $requestData)
+ {
+ return parent::discard($id, $requestData);
+ }
+}
\ No newline at end of file
diff --git a/libraries/default/RequestProcessors/SynchronisationRequestProcessor.php b/libraries/default/RequestProcessors/SynchronisationRequestProcessor.php
new file mode 100644
index 0000000..ae63ad5
--- /dev/null
+++ b/libraries/default/RequestProcessors/SynchronisationRequestProcessor.php
@@ -0,0 +1,65 @@
+description = __('Handle exchange of data between two cerebrate instances');
+ $this->Users = TableRegistry::getTableLocator()->get('Users');
+ }
+
+ protected function addValidatorRules($validator)
+ {
+ return $validator;
+ }
+
+ public function create($requestData) {
+ $this->validateRequestData($requestData);
+ $requestData['title'] = __('Data exchange requested for record `{0}`', 'recordname');
+ return parent::create($requestData);
+ }
+
+ public function process($id, $requestData)
+ {
+ $dataExchangeAccepted = false;
+ $saveResult = [];
+ if ($dataExchangeAccepted) {
+ $this->discard($id, $requestData);
+ }
+ return $this->genActionResult(
+ $saveResult,
+ $dataExchangeAccepted,
+ $dataExchangeAccepted ? __('Record `{0}` exchanged', 'recordname') : __('Could not exchange record `{0}`.', 'recordname'),
+ []
+ );
+ }
+
+ public function discard($id, $requestData)
+ {
+ return parent::discard($id, $requestData);
+ }
+}
\ No newline at end of file
diff --git a/libraries/default/RequestProcessors/TemplateRequestProcessor.php.template b/libraries/default/RequestProcessors/TemplateRequestProcessor.php.template
new file mode 100644
index 0000000..6adb4c0
--- /dev/null
+++ b/libraries/default/RequestProcessors/TemplateRequestProcessor.php.template
@@ -0,0 +1,65 @@
+description = __('~to-be-defined~');
+ $this->Users = TableRegistry::getTableLocator()->get('Users');
+ }
+
+ protected function addValidatorRules($validator)
+ {
+ return $validator;
+ }
+
+ public function create($requestData) {
+ $this->validateRequestData($requestData);
+ $requestData['title'] = __('~to-be-defined~');
+ return parent::create($requestData);
+ }
+
+ public function process($id, $requestData)
+ {
+ $proposalAccepted = false;
+ $saveResult = [];
+ if ($proposalAccepted) {
+ $this->discard($id, $requestData);
+ }
+ return $this->genActionResult(
+ $saveResult,
+ $proposalAccepted,
+ $proposalAccepted ? __('success') : __('fail'),
+ []
+ );
+ }
+
+ public function discard($id, $requestData)
+ {
+ return parent::discard($id, $requestData);
+ }
+}
\ No newline at end of file
diff --git a/libraries/default/RequestProcessors/UserRequestProcessor.php b/libraries/default/RequestProcessors/UserRequestProcessor.php
new file mode 100644
index 0000000..3120bde
--- /dev/null
+++ b/libraries/default/RequestProcessors/UserRequestProcessor.php
@@ -0,0 +1,121 @@
+Users = TableRegistry::getTableLocator()->get('Users');
+ }
+
+ public function create($requestData)
+ {
+ return parent::create($requestData);
+ }
+}
+
+class RegistrationProcessor extends UserRequestProcessor implements GenericProcessorActionI {
+ public $action = 'Registration';
+ protected $description;
+
+ public function __construct() {
+ parent::__construct();
+ $this->description = __('Handle user account for this cerebrate instance');
+ }
+
+ protected function addValidatorRules($validator)
+ {
+ return $validator
+ ->notEmpty('username', 'A username must be provided.')
+ ->add('email', 'validFormat', [
+ 'rule' => 'email',
+ 'message' => 'E-mail must be valid'
+ ])
+ ->notEmpty('first_name', 'A first name must be provided')
+ ->notEmpty('last_name', 'A last name must be provided');
+ }
+
+ public function create($requestData) {
+ $this->validateRequestData($requestData);
+ $requestData['title'] = __('User account creation requested for {0}', $requestData['data']['email']);
+ return parent::create($requestData);
+ }
+
+ public function getViewVariables($request)
+ {
+ $dropdownData = [
+ 'role' => $this->Users->Roles->find('list', [
+ 'sort' => ['name' => 'asc']
+ ]),
+ 'individual' => [-1 => __('-- New individual --')] + $this->Users->Individuals->find('list', [
+ 'sort' => ['email' => 'asc']
+ ])->toArray()
+ ];
+ $individualEntity = $this->Users->Individuals->newEntity([
+ 'email' => !empty($request['data']['email']) ? $request['data']['email'] : '',
+ 'first_name' => !empty($request['data']['first_name']) ? $request['data']['first_name'] : '',
+ 'last_name' => !empty($request['data']['last_name']) ? $request['data']['last_name'] : '',
+ 'position' => !empty($request['data']['position']) ? $request['data']['position'] : '',
+ ]);
+ $userEntity = $this->Users->newEntity([
+ 'individual_id' => -1,
+ 'username' => !empty($request['data']['username']) ? $request['data']['username'] : '',
+ 'role_id' => !empty($request['data']['role_id']) ? $request['data']['role_id'] : '',
+ 'disabled' => !empty($request['data']['disabled']) ? $request['data']['disabled'] : '',
+ ]);
+ return [
+ 'dropdownData' => $dropdownData,
+ 'userEntity' => $userEntity,
+ 'individualEntity' => $individualEntity
+ ];
+ }
+
+ public function process($id, $requestData)
+ {
+ if ($requestData['individual_id'] == -1) {
+ $individual = $this->Users->Individuals->newEntity([
+ 'uuid' => $requestData['uuid'],
+ 'email' => $requestData['email'],
+ 'first_name' => $requestData['first_name'],
+ 'last_name' => $requestData['last_name'],
+ 'position' => $requestData['position'],
+ ]);
+ $individual = $this->Users->Individuals->save($individual);
+ } else {
+ $individual = $this->Users->Individuals->get($requestData['individual_id']);
+ }
+ $user = $this->Users->newEntity([
+ 'individual_id' => $individual->id,
+ 'username' => $requestData['username'],
+ 'password' => '~PASSWORD_TO_BE_REPLACED~',
+ 'role_id' => $requestData['role_id'],
+ 'disabled' => $requestData['disabled'],
+ ]);
+ $user = $this->Users->save($user);
+
+ if ($user !== false) {
+ $this->discard($id, $requestData);
+ }
+ return $this->genActionResult(
+ $user,
+ $user !== false,
+ $user !== false ? __('User `{0}` created', $user->username) : __('Could not create user `{0}`.', $user->username),
+ $user->getErrors()
+ );
+ }
+
+ public function discard($id, $requestData)
+ {
+ return parent::discard($id, $requestData);
+ }
+}
\ No newline at end of file
diff --git a/libraries/default/RequestProcessors/templates/User/registration.php b/libraries/default/RequestProcessors/templates/User/registration.php
new file mode 100644
index 0000000..ebcc819
--- /dev/null
+++ b/libraries/default/RequestProcessors/templates/User/registration.php
@@ -0,0 +1,125 @@
+element('genericElements/Form/genericForm', [
+ 'entity' => $userEntity,
+ 'ajax' => false,
+ 'raw' => true,
+ 'data' => [
+ 'description' => __('Create user account'),
+ 'model' => 'User',
+ 'fields' => [
+ [
+ 'field' => 'individual_id',
+ 'type' => 'dropdown',
+ 'label' => __('Associated individual'),
+ 'options' => $dropdownData['individual'],
+ ],
+ [
+ 'field' => 'username',
+ 'autocomplete' => 'off',
+ ],
+ [
+ 'field' => 'role_id',
+ 'type' => 'dropdown',
+ 'label' => __('Role'),
+ 'options' => $dropdownData['role']
+ ],
+ [
+ 'field' => 'disabled',
+ 'type' => 'checkbox',
+ 'label' => 'Disable'
+ ]
+ ],
+ 'submit' => [
+ 'action' => $this->request->getParam('action')
+ ]
+ ]
+ ]);
+
+ $formIndividual = $this->element('genericElements/Form/genericForm', [
+ 'entity' => $individualEntity,
+ 'ajax' => false,
+ 'raw' => true,
+ 'data' => [
+ 'description' => __('Create individual'),
+ 'model' => 'Individual',
+ 'fields' => [
+ [
+ 'field' => 'email',
+ 'autocomplete' => 'off'
+ ],
+ [
+ 'field' => 'uuid',
+ 'label' => 'UUID',
+ 'type' => 'uuid',
+ 'autocomplete' => 'off'
+ ],
+ [
+ 'field' => 'first_name',
+ 'autocomplete' => 'off'
+ ],
+ [
+ 'field' => 'last_name',
+ 'autocomplete' => 'off'
+ ],
+ [
+ 'field' => 'position',
+ 'autocomplete' => 'off'
+ ],
+ ],
+ 'submit' => [
+ 'action' => $this->request->getParam('action')
+ ]
+ ]
+ ]);
+
+ echo $this->Bootstrap->modal([
+ 'title' => __('Register user'),
+ 'size' => 'lg',
+ 'type' => 'confirm',
+ 'bodyHtml' => sprintf('
%s
%s
',
+ $formUser,
+ $formIndividual
+ ),
+ 'confirmText' => __('Create user'),
+ 'confirmFunction' => 'submitRegistration'
+ ]);
+?>
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php
index 87f968d..70116d9 100644
--- a/src/Controller/AppController.php
+++ b/src/Controller/AppController.php
@@ -107,6 +107,12 @@ class AppController extends Controller
} else if ($this->ParamHandler->isRest()) {
throw new MethodNotAllowedException(__('Invalid user credentials.'));
}
+
+ if ($this->request->getParam('action') === 'index') {
+ $this->Security->setConfig('validatePost', false);
+ }
+ $this->Security->setConfig('unlockedActions', ['index']);
+
$this->ACL->checkAccess();
$this->set('menu', $this->ACL->getMenu());
$this->set('ajax', $this->request->is('ajax'));
diff --git a/src/Controller/BroodsController.php b/src/Controller/BroodsController.php
index 7796324..d954f77 100644
--- a/src/Controller/BroodsController.php
+++ b/src/Controller/BroodsController.php
@@ -6,6 +6,7 @@ use App\Controller\AppController;
use Cake\Utility\Hash;
use Cake\Utility\Text;
use \Cake\Database\Expression\QueryExpression;
+use Cake\ORM\TableRegistry;
class BroodsController extends AppController
{
@@ -154,4 +155,22 @@ class BroodsController extends AppController
$this->redirect($this->referer());
}
}
+
+ public function interconnectTools()
+ {
+ $this->requestProcessor = TableRegistry::getTableLocator()->get('RequestProcessor');
+ $processor = $this->requestProcessor->getProcessor('Brood', 'ToolInterconnection');
+ $data = [
+ 'origin' => '127.0.0.1',
+ 'comment' => 'Test comment',
+ 'user_id' => $this->ACL->getUser()->id,
+ 'data' => [
+ 'foo' => 'foo',
+ 'bar' => 'bar',
+ 'baz' => 'baz',
+ ],
+ ];
+ $processorResult = $processor->create($data);
+ return $processor->genHTTPReply($this, $processorResult, ['controller' => 'Broods', 'action' => 'index']);
+ }
}
diff --git a/src/Controller/Component/ACLComponent.php b/src/Controller/Component/ACLComponent.php
index 2a5a648..eec94ce 100644
--- a/src/Controller/Component/ACLComponent.php
+++ b/src/Controller/Component/ACLComponent.php
@@ -642,6 +642,29 @@ class ACLComponent extends Component
]
]
],
+ 'Inbox' => [
+ 'label' => __('Inbox'),
+ 'url' => '/inbox/index',
+ 'children' => [
+ 'index' => [
+ 'url' => '/inbox/index',
+ 'label' => __('Inbox')
+ ],
+ 'view' => [
+ 'url' => '/inbox/view/{{id}}',
+ 'label' => __('View Meta Template'),
+ 'actions' => ['delete', 'edit', 'view'],
+ 'skipTopMenu' => 1
+ ],
+ 'delete' => [
+ 'url' => '/inbox/delete/{{id}}',
+ 'label' => __('Delete Meta Template'),
+ 'actions' => ['delete', 'edit', 'view'],
+ 'skipTopMenu' => 1,
+ 'popup' => 1
+ ]
+ ]
+ ],
'MetaTemplates' => [
'label' => __('Meta Field Templates'),
'url' => '/metaTemplates/index',
diff --git a/src/Controller/Component/CRUDComponent.php b/src/Controller/Component/CRUDComponent.php
index 32d3717..31de16c 100644
--- a/src/Controller/Component/CRUDComponent.php
+++ b/src/Controller/Component/CRUDComponent.php
@@ -165,7 +165,7 @@ class CRUDComponent extends Component
$message = __(
'{0} could not be added.{1}',
$this->ObjectAlias,
- empty($validationMessage) ? '' : ' ' . __('Reason:{0}', $validationMessage)
+ empty($validationMessage) ? '' : PHP_EOL . __('Reason:{0}', $validationMessage)
);
if ($this->Controller->ParamHandler->isRest()) {
} else if ($this->Controller->ParamHandler->isAjax()) {
@@ -508,7 +508,7 @@ class CRUDComponent extends Component
if (is_bool($contextFromField)) {
$contextFromFieldText = sprintf('%s: %s', $field, $contextFromField ? 'true' : 'false');
} else {
- $contextFromFieldText = $contextFromField;
+ $contextFromFieldText = sprintf('%s: %s', $field, $contextFromField);
}
$filteringContexts[] = [
'label' => Inflector::humanize($contextFromFieldText),
diff --git a/src/Controller/Component/RestResponseComponent.php b/src/Controller/Component/RestResponseComponent.php
index 96b3725..4a7346f 100644
--- a/src/Controller/Component/RestResponseComponent.php
+++ b/src/Controller/Component/RestResponseComponent.php
@@ -423,11 +423,12 @@ class RestResponseComponent extends Component
public function ajaxSuccessResponse($ObjectAlias, $action, $entity, $message, $additionalData=[])
{
$action = $this->__dissectAdminRouting($action);
+ $entity = is_array($entity) ? $entity : $entity->toArray();
$response = [
'success' => true,
'message' => $message,
- 'data' => $entity->toArray()
- //'url' => $this->__generateURL($action, $ObjectAlias, $entity->id)
+ 'data' => $entity,
+ 'url' => !empty($entity['id']) ? $this->__generateURL($action, $ObjectAlias, $entity['id']) : ''
];
if (!empty($additionalData)) {
$response['additionalData'] = $additionalData;
@@ -438,11 +439,12 @@ class RestResponseComponent extends Component
public function ajaxFailResponse($ObjectAlias, $action, $entity, $message, $errors = [])
{
$action = $this->__dissectAdminRouting($action);
+ $entity = is_array($entity) ? $entity : $entity->toArray();
$response = [
'success' => false,
'message' => $message,
'errors' => $errors,
- 'url' => $this->__generateURL($action, $ObjectAlias, $entity->id)
+ 'url' => !empty($entity['id']) ? $this->__generateURL($action, $ObjectAlias, $entity['id']) : ''
];
return $this->viewData($response);
}
diff --git a/src/Controller/EncryptionKeysController.php b/src/Controller/EncryptionKeysController.php
index afcc611..a9bf699 100644
--- a/src/Controller/EncryptionKeysController.php
+++ b/src/Controller/EncryptionKeysController.php
@@ -18,7 +18,7 @@ class EncryptionKeysController extends AppController
{
$this->CRUD->index([
'quickFilters' => ['encryption_key'],
- 'filters' => ['owner_type', 'organisation_id', 'individual_id', 'encryption_key'],
+ 'filters' => ['owner_model', 'organisation_id', 'individual_id', 'encryption_key'],
'contextFilters' => [
'fields' => [
'type'
diff --git a/src/Controller/InboxController.php b/src/Controller/InboxController.php
new file mode 100644
index 0000000..6c0f978
--- /dev/null
+++ b/src/Controller/InboxController.php
@@ -0,0 +1,131 @@
+set('metaGroup', 'Administration');
+ }
+
+
+ public function index()
+ {
+ $this->CRUD->index([
+ 'filters' => $this->filters,
+ 'quickFilters' => ['scope', 'action', ['title' => true], ['comment' => true]],
+ 'contextFilters' => [
+ 'fields' => [
+ 'scope',
+ 'action',
+ ]
+ ],
+ 'contain' => ['Users']
+ ]);
+ $responsePayload = $this->CRUD->getResponsePayload();
+ if (!empty($responsePayload)) {
+ return $responsePayload;
+ }
+ }
+
+ public function filtering()
+ {
+ $this->CRUD->filtering();
+ }
+
+ public function view($id)
+ {
+ $this->CRUD->view($id);
+ $responsePayload = $this->CRUD->getResponsePayload();
+ if (!empty($responsePayload)) {
+ return $responsePayload;
+ }
+ }
+
+ public function delete($id)
+ {
+ if ($this->request->is('post')) {
+ $request = $this->Inbox->get($id);
+ $this->requestProcessor = TableRegistry::getTableLocator()->get('RequestProcessor');
+ $processor = $this->requestProcessor->getProcessor($request->scope, $request->action);
+ $discardResult = $processor->discard($id, $request);
+ return $processor->genHTTPReply($this, $discardResult);
+ }
+ $this->set('deletionTitle', __('Discard request'));
+ $this->set('deletionText', __('Are you sure you want to discard request #{0}?', $id));
+ $this->set('deletionConfirm', __('Discard'));
+ $this->CRUD->delete($id);
+ $responsePayload = $this->CRUD->getResponsePayload();
+ if (!empty($responsePayload)) {
+ return $responsePayload;
+ }
+ }
+
+ public function process($id)
+ {
+ $request = $this->Inbox->get($id);
+ $scope = $request->scope;
+ $action = $request->action;
+ $this->requestProcessor = TableRegistry::getTableLocator()->get('RequestProcessor');
+ $processor = $this->requestProcessor->getProcessor($request->scope, $request->action);
+ if ($this->request->is('post')) {
+ $processResult = $processor->process($id, $this->request->getData());
+ return $processor->genHTTPReply($this, $processResult);
+ } else {
+ $renderedView = $processor->render($request);
+ return $this->response->withStringBody($renderedView);
+ }
+ }
+
+ public function listProcessors()
+ {
+ $this->requestProcessor = TableRegistry::getTableLocator()->get('RequestProcessor');
+ $requestProcessors = $this->requestProcessor->listProcessors();
+ if ($this->ParamHandler->isRest()) {
+ return $this->RestResponse->viewData($requestProcessors, 'json');
+ }
+ $data = [];
+ foreach ($requestProcessors as $scope => $processors) {
+ foreach ($processors as $processor) {
+ $data[] = [
+ 'enabled' => $processor->enabled,
+ 'scope' => $scope,
+ 'action' => $processor->action
+ ];
+ }
+ }
+ $this->set('title', 'Available request processors');
+ $this->set('fields', [
+ [
+ 'name' => 'Enabled',
+ 'data_path' => 'enabled',
+ 'element' => 'boolean'
+ ],
+ [
+ 'name' => 'Processor scope',
+ 'data_path' => 'scope',
+ ],
+ [
+ 'name' => 'Processor action',
+ 'data_path' => 'action',
+ ]
+ ]);
+ $this->set('data', $data);
+ $this->render('/genericTemplates/index_simple');
+ }
+}
diff --git a/src/Controller/UsersController.php b/src/Controller/UsersController.php
index dadca75..8a40151 100644
--- a/src/Controller/UsersController.php
+++ b/src/Controller/UsersController.php
@@ -4,6 +4,7 @@ namespace App\Controller;
use App\Controller\AppController;
use Cake\Utility\Hash;
use Cake\Utility\Text;
+use Cake\ORM\TableRegistry;
use \Cake\Database\Expression\QueryExpression;
class UsersController extends AppController
@@ -134,4 +135,22 @@ class UsersController extends AppController
return $this->redirect(\Cake\Routing\Router::url('/users/login'));
}
}
+
+ public function register()
+ {
+ $this->requestProcessor = TableRegistry::getTableLocator()->get('RequestProcessor');
+ $processor = $this->requestProcessor->getProcessor('User', 'Registration');
+ $data = [
+ 'origin' => '127.0.0.1',
+ 'comment' => 'Hi there!, please create an account',
+ 'data' => [
+ 'username' => 'foobar',
+ 'email' => 'foobar@admin.test',
+ 'first_name' => 'foo',
+ 'last_name' => 'bar',
+ ],
+ ];
+ $processorResult = $processor->create($data);
+ return $processor->genHTTPReply($this, $processorResult, ['controller' => 'Inbox', 'action' => 'index']);
+ }
}
diff --git a/src/Model/Entity/Inbox.php b/src/Model/Entity/Inbox.php
new file mode 100644
index 0000000..a8f546e
--- /dev/null
+++ b/src/Model/Entity/Inbox.php
@@ -0,0 +1,11 @@
+ 'owner_id',
- 'conditions' => ['owner_type' => 'individual']
+ 'conditions' => ['owner_model' => 'individual']
]
);
$this->belongsTo(
'Organisations',
[
'foreignKey' => 'owner_id',
- 'conditions' => ['owner_type' => 'organisation']
+ 'conditions' => ['owner_model' => 'organisation']
]
);
$this->setDisplayField('encryption_key');
@@ -34,13 +34,13 @@ class EncryptionKeysTable extends AppTable
public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options)
{
if (empty($data['owner_id'])) {
- if (empty($data['owner_type'])) {
+ if (empty($data['owner_model'])) {
return false;
}
- if (empty($data[$data['owner_type'] . '_id'])) {
+ if (empty($data[$data['owner_model'] . '_id'])) {
return false;
}
- $data['owner_id'] = $data[$data['owner_type'] . '_id'];
+ $data['owner_id'] = $data[$data['owner_model'] . '_id'];
}
}
@@ -50,8 +50,8 @@ class EncryptionKeysTable extends AppTable
->notEmptyString('type')
->notEmptyString('encryption_key')
->notEmptyString('owner_id')
- ->notEmptyString('owner_type')
- ->requirePresence(['type', 'encryption_key', 'owner_id', 'owner_type'], 'create');
+ ->notEmptyString('owner_model')
+ ->requirePresence(['type', 'encryption_key', 'owner_id', 'owner_model'], 'create');
return $validator;
}
}
diff --git a/src/Model/Table/InboxTable.php b/src/Model/Table/InboxTable.php
new file mode 100644
index 0000000..93a7f22
--- /dev/null
+++ b/src/Model/Table/InboxTable.php
@@ -0,0 +1,65 @@
+addBehavior('UUID');
+ $this->addBehavior('Timestamp', [
+ 'events' => [
+ 'Model.beforeSave' => [
+ 'created' => 'new'
+ ]
+ ]
+ ]);
+
+ $this->belongsTo('Users');
+ $this->setDisplayField('title');
+ }
+
+ protected function _initializeSchema(TableSchemaInterface $schema): TableSchemaInterface
+ {
+ $schema->setColumnType('data', 'json');
+
+ return $schema;
+ }
+
+ public function validationDefault(Validator $validator): Validator
+ {
+ $validator
+ ->notEmptyString('scope')
+ ->notEmptyString('action')
+ ->notEmptyString('title')
+ ->notEmptyString('origin')
+ ->datetime('created')
+
+ ->requirePresence([
+ 'scope' => ['message' => __('The field `scope` is required')],
+ 'action' => ['message' => __('The field `action` is required')],
+ 'title' => ['message' => __('The field `title` is required')],
+ 'origin' => ['message' => __('The field `origin` is required')],
+ ], 'create');
+ return $validator;
+ }
+
+ public function buildRules(RulesChecker $rules): RulesChecker
+ {
+ $rules->add($rules->existsIn('user_id', 'Users'), [
+ 'message' => 'The provided `user_id` does not exist'
+ ]);
+
+ return $rules;
+ }
+}
diff --git a/src/Model/Table/IndividualsTable.php b/src/Model/Table/IndividualsTable.php
index 1611a5f..d0df577 100644
--- a/src/Model/Table/IndividualsTable.php
+++ b/src/Model/Table/IndividualsTable.php
@@ -25,7 +25,7 @@ class IndividualsTable extends AppTable
'EncryptionKeys',
[
'foreignKey' => 'owner_id',
- 'conditions' => ['owner_type' => 'individual']
+ 'conditions' => ['owner_model' => 'individual']
]
);
$this->hasOne(
diff --git a/src/Model/Table/OrganisationsTable.php b/src/Model/Table/OrganisationsTable.php
index 446d3fa..c23ee7b 100644
--- a/src/Model/Table/OrganisationsTable.php
+++ b/src/Model/Table/OrganisationsTable.php
@@ -30,7 +30,7 @@ class OrganisationsTable extends AppTable
[
'dependent' => true,
'foreignKey' => 'owner_id',
- 'conditions' => ['owner_type' => 'organisation']
+ 'conditions' => ['owner_model' => 'organisation']
]
);
$this->hasMany(
diff --git a/src/Model/Table/RequestProcessorTable.php b/src/Model/Table/RequestProcessorTable.php
new file mode 100644
index 0000000..e76fdab
--- /dev/null
+++ b/src/Model/Table/RequestProcessorTable.php
@@ -0,0 +1,95 @@
+ [
+ 'ToolInterconnection' => false,
+ 'OneWaySynchronization' => false,
+ ],
+ 'Proposal' => [
+ 'ProposalEdit' => false,
+ ],
+ 'Synchronisation' => [
+ 'DataExchange' => false,
+ ],
+ 'User' => [
+ 'Registration' => true,
+ ],
+ ];
+
+ public function initialize(array $config): void
+ {
+ parent::initialize($config);
+ $this->loadProcessors();
+ }
+
+ public function getProcessor($scope, $action=null)
+ {
+ if (isset($this->requestProcessors[$scope])) {
+ if (is_null($action)) {
+ return $this->requestProcessors[$scope];
+ } else if (!empty($this->requestProcessors[$scope]->{$action})) {
+ return $this->requestProcessors[$scope]->{$action};
+ } else {
+ throw new \Exception(__('Processor {0}.{1} not found', $scope, $action));
+ }
+ }
+ throw new \Exception(__('Processor not found'), 1);
+ }
+
+ public function listProcessors($scope=null)
+ {
+ if (is_null($scope)) {
+ return $this->requestProcessors;
+ } else {
+ if (isset($this->requestProcessors[$scope])) {
+ return $this->requestProcessors[$scope];
+ } else {
+ throw new \Exception(__('Processors for {0} not found', $scope));
+ }
+ }
+ }
+
+ private function loadProcessors()
+ {
+ $processorDir = new Folder($this->processorsDirectory);
+ $processorFiles = $processorDir->find('.*RequestProcessor\.php', true);
+ foreach ($processorFiles as $processorFile) {
+ if ($processorFile == 'GenericRequestProcessor.php') {
+ continue;
+ }
+ $processorMainClassName = str_replace('.php', '', $processorFile);
+ $processorMainClassNameShort = str_replace('RequestProcessor.php', '', $processorFile);
+ $processorMainClass = $this->getProcessorClass($processorDir->pwd() . DS . $processorFile, $processorMainClassName);
+ if ($processorMainClass !== false) {
+ $this->requestProcessors[$processorMainClassNameShort] = $processorMainClass;
+ foreach ($this->requestProcessors[$processorMainClassNameShort]->getRegisteredActions() as $registeredAction) {
+ $scope = $this->requestProcessors[$processorMainClassNameShort]->getScope();
+ if (!empty($this->enabledProcessors[$scope][$registeredAction])) {
+ $this->requestProcessors[$processorMainClassNameShort]->{$registeredAction}->enabled = true;
+ } else {
+ $this->requestProcessors[$processorMainClassNameShort]->{$registeredAction}->enabled = false;
+ }
+ }
+ }
+ }
+ }
+
+ private function getProcessorClass($filePath, $processorMainClassName)
+ {
+ require_once($filePath);
+ $reflection = new \ReflectionClass($processorMainClassName);
+ $processorMainClass = $reflection->newInstance(true);
+ if ($processorMainClass->checkLoading() === 'Assimilation successful!') {
+ return $processorMainClass;
+ }
+ }
+}
diff --git a/src/View/Helper/BootstrapHelper.php b/src/View/Helper/BootstrapHelper.php
index 2309d87..b63e5f6 100644
--- a/src/View/Helper/BootstrapHelper.php
+++ b/src/View/Helper/BootstrapHelper.php
@@ -721,7 +721,7 @@ class BoostrapModal extends BootstrapGeneric {
'footerClass' => [''],
'type' => 'ok-only',
'variant' => '',
- 'confirmFunction' => '',
+ 'confirmFunction' => '', // Will be called with the following arguments confirmFunction(modalObject, tmpApi)
'cancelFunction' => ''
];
@@ -822,7 +822,7 @@ class BoostrapModal extends BootstrapGeneric {
'variant' => 'primary',
'text' => __('Ok'),
'params' => [
- 'data-dismiss' => 'modal',
+ 'data-dismiss' => $this->options['confirmFunction'] ? '' : 'modal',
'onclick' => $this->options['confirmFunction']
]
]))->button();
@@ -847,9 +847,10 @@ class BoostrapModal extends BootstrapGeneric {
$buttonConfirm = (new BoostrapButton([
'variant' => $variant,
'text' => h($this->options['confirmText']),
+ 'class' => 'modal-confirm-button',
'params' => [
- 'data-dismiss' => 'modal',
- 'onclick' => $this->options['confirmFunction']
+ 'data-dismiss' => $this->options['confirmFunction'] ? '' : 'modal',
+ 'data-confirmFunction' => sprintf('%s', $this->options['confirmFunction'])
]
]))->button();
return $buttonCancel . $buttonConfirm;
diff --git a/src/View/MonadView.php b/src/View/MonadView.php
new file mode 100644
index 0000000..6c72ef3
--- /dev/null
+++ b/src/View/MonadView.php
@@ -0,0 +1,34 @@
+additionalTemplatePaths);
+ return $paths;
+ }
+}
diff --git a/templates/EncryptionKeys/add.php b/templates/EncryptionKeys/add.php
index 6a80c39..3f1800e 100644
--- a/templates/EncryptionKeys/add.php
+++ b/templates/EncryptionKeys/add.php
@@ -6,7 +6,7 @@ echo $this->element('genericElements/Form/genericForm', [
'model' => 'Organisations',
'fields' => [
[
- 'field' => 'owner_type',
+ 'field' => 'owner_model',
'label' => __('Owner type'),
'options' => array_combine(array_keys($dropdownData), array_keys($dropdownData)),
'type' => 'dropdown'
@@ -17,7 +17,7 @@ echo $this->element('genericElements/Form/genericForm', [
'options' => $dropdownData['organisation'] ?? [],
'type' => 'dropdown',
'stateDependence' => [
- 'source' => '#owner_type-field',
+ 'source' => '#owner_model-field',
'option' => 'organisation'
]
],
@@ -27,7 +27,7 @@ echo $this->element('genericElements/Form/genericForm', [
'options' => $dropdownData['individual'] ?? [],
'type' => 'dropdown',
'stateDependence' => [
- 'source' => '#owner_type-field',
+ 'source' => '#owner_model-field',
'option' => 'individual'
]
],
diff --git a/templates/EncryptionKeys/index.php b/templates/EncryptionKeys/index.php
index fed2abd..5017319 100644
--- a/templates/EncryptionKeys/index.php
+++ b/templates/EncryptionKeys/index.php
@@ -45,7 +45,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
[
'name' => __('Owner'),
'data_path' => 'owner_id',
- 'owner_type_path' => 'owner_type',
+ 'owner_model_path' => 'owner_model',
'element' => 'owner'
],
[
diff --git a/templates/Inbox/index.php b/templates/Inbox/index.php
new file mode 100644
index 0000000..55eabd3
--- /dev/null
+++ b/templates/Inbox/index.php
@@ -0,0 +1,99 @@
+Html->scriptBlock(sprintf(
+ 'var csrfToken = %s;',
+ json_encode($this->request->getAttribute('csrfToken'))
+));
+echo $this->element('genericElements/IndexTable/index_table', [
+ 'data' => [
+ 'data' => $data,
+ 'top_bar' => [
+ 'children' => [
+ [
+ 'type' => 'context_filters',
+ 'context_filters' => !empty($filteringContexts) ? $filteringContexts : []
+ ],
+ [
+ 'type' => 'search',
+ 'button' => __('Filter'),
+ 'placeholder' => __('Enter value to search'),
+ 'data' => '',
+ 'searchKey' => 'value',
+ 'allowFilering' => true
+ ]
+ ]
+ ],
+ 'fields' => [
+ [
+ 'name' => '#',
+ 'sort' => 'id',
+ 'data_path' => 'id',
+ ],
+ [
+ 'name' => 'created',
+ 'sort' => 'created',
+ 'data_path' => 'created',
+ 'element' => 'datetime'
+ ],
+ [
+ 'name' => 'scope',
+ 'sort' => 'scope',
+ 'data_path' => 'scope',
+ ],
+ [
+ 'name' => 'action',
+ 'sort' => 'action',
+ 'data_path' => 'action',
+ ],
+ [
+ 'name' => 'title',
+ 'sort' => 'title',
+ 'data_path' => 'title',
+ ],
+ [
+ 'name' => 'origin',
+ 'sort' => 'origin',
+ 'data_path' => 'origin',
+ ],
+ [
+ 'name' => 'user',
+ 'sort' => 'user_id',
+ 'data_path' => 'user',
+ 'element' => 'user'
+ ],
+ [
+ 'name' => 'description',
+ 'sort' => 'description',
+ 'data_path' => 'description',
+ ],
+ [
+ 'name' => 'comment',
+ 'sort' => 'comment',
+ 'data_path' => 'comment',
+ ],
+ ],
+ 'title' => __('Inbox'),
+ 'description' => __('A list of requests to be manually processed'),
+ 'actions' => [
+ [
+ 'url' => '/inbox/view',
+ 'url_params_data_paths' => ['id'],
+ 'icon' => 'eye',
+ 'title' => __('View request')
+ ],
+ [
+ 'open_modal' => '/inbox/process/[onclick_params_data_path]',
+ 'modal_params_data_path' => 'id',
+ 'icon' => 'cogs',
+ 'title' => __('Process request')
+ ],
+ [
+ 'open_modal' => '/inbox/delete/[onclick_params_data_path]',
+ 'modal_params_data_path' => 'id',
+ 'icon' => 'trash',
+ 'title' => __('Discard request')
+ ],
+ ]
+ ]
+]);
+echo '';
+?>
diff --git a/templates/Inbox/view.php b/templates/Inbox/view.php
new file mode 100644
index 0000000..36e0dfc
--- /dev/null
+++ b/templates/Inbox/view.php
@@ -0,0 +1,51 @@
+element(
+ '/genericElements/SingleViews/single_view',
+ [
+ 'data' => $entity,
+ 'fields' => [
+ [
+ 'key' => __('ID'),
+ 'path' => 'id'
+ ],
+ [
+ 'key' => 'created',
+ 'path' => 'created',
+ ],
+ [
+ 'key' => 'scope',
+ 'path' => 'scope',
+ ],
+ [
+ 'key' => 'action',
+ 'path' => 'action',
+ ],
+ [
+ 'key' => 'title',
+ 'path' => 'title',
+ ],
+ [
+ 'key' => 'origin',
+ 'path' => 'origin',
+ ],
+ [
+ 'key' => 'user_id',
+ 'path' => 'user_id',
+ ],
+ [
+ 'key' => 'description',
+ 'path' => 'description',
+ ],
+ [
+ 'key' => 'comment',
+ 'path' => 'comment',
+ ],
+ [
+ 'key' => 'data',
+ 'path' => 'data',
+ 'type' => 'json'
+ ],
+ ],
+ 'children' => []
+ ]
+);
diff --git a/templates/Instance/migration_index.php b/templates/Instance/migration_index.php
index b554dd1..f2bef2e 100644
--- a/templates/Instance/migration_index.php
+++ b/templates/Instance/migration_index.php
@@ -51,7 +51,7 @@ function runAllUpdate() {
type: 'confirm-success',
confirmText: '= __n('Run update', 'Run all updates', count($updateAvailables)) ?>',
APIConfirm: (tmpApi) => {
- tmpApi.fetchAndPostForm(url, {}).then(() => {
+ return tmpApi.fetchAndPostForm(url, {}).then(() => {
location.reload()
})
},
diff --git a/templates/element/genericElements/Form/genericForm.php b/templates/element/genericElements/Form/genericForm.php
index 6e642ff..9e3ba2e 100644
--- a/templates/element/genericElements/Form/genericForm.php
+++ b/templates/element/genericElements/Form/genericForm.php
@@ -115,6 +115,24 @@
'actionButton' => $this->element('genericElements/Form/submitButton', $submitButtonData),
'class' => 'modal-lg'
]);
+ } else if (!empty($raw)) {
+ echo sprintf(
+ '%s%s%s%s%s%s',
+ empty($data['description']) ? '' : sprintf(
+ '%s
',
+ $data['description']
+ ),
+ $ajaxFlashMessage,
+ $formCreate,
+ $fieldsString,
+ empty($metaTemplateString) ? '' : $this->element(
+ 'genericElements/accordion_scaffold', [
+ 'body' => $metaTemplateString,
+ 'title' => 'Meta fields'
+ ]
+ ),
+ $formEnd
+ );
} else {
echo sprintf(
'%s%s
%s%s%s%s%s%s%s%s%s',
diff --git a/templates/element/genericElements/Form/submitButton.php b/templates/element/genericElements/Form/submitButton.php
index 9a2a82c..134e857 100644
--- a/templates/element/genericElements/Form/submitButton.php
+++ b/templates/element/genericElements/Form/submitButton.php
@@ -3,7 +3,7 @@
echo sprintf(
'%s',
sprintf(
- '',
+ '',
'#form-' . h($formRandomValue),
__('Submit')
)
diff --git a/templates/element/genericElements/IndexTable/Fields/actions.php b/templates/element/genericElements/IndexTable/Fields/actions.php
index 4e4bf61..e0d275b 100644
--- a/templates/element/genericElements/IndexTable/Fields/actions.php
+++ b/templates/element/genericElements/IndexTable/Fields/actions.php
@@ -97,7 +97,7 @@
);
}
$reload_url = !empty($action['reload_url']) ? $action['reload_url'] : $this->Url->build(['action' => 'index']);
- $action['onclick'] = sprintf('UI.openModalFromURL(\'%s\', \'%s\', \'%s\')', $modal_url, $reload_url, $tableRandomValue);
+ $action['onclick'] = sprintf('UI.submissionModalForIndex(\'%s\', \'%s\', \'%s\')', $modal_url, $reload_url, $tableRandomValue);
}
echo sprintf(
' ',
diff --git a/templates/element/genericElements/IndexTable/Fields/alignments.php b/templates/element/genericElements/IndexTable/Fields/alignments.php
index 611f990..f761c2a 100644
--- a/templates/element/genericElements/IndexTable/Fields/alignments.php
+++ b/templates/element/genericElements/IndexTable/Fields/alignments.php
@@ -14,7 +14,7 @@ if ($field['scope'] === 'individuals') {
h($alignment['organisation']['name'])
),
!$canRemove ? '' : sprintf(
- "UI.openModalFromURL(%s);",
+ "UI.submissionModalForIndex(%s);",
sprintf(
"'/alignments/delete/%s'",
h($alignment['id'])
@@ -34,7 +34,7 @@ if ($field['scope'] === 'individuals') {
h($alignment['individual']['email'])
),
!$canRemove ? '' : sprintf(
- "UI.openModalFromURL(%s);",
+ "UI.submissionModalForIndex(%s);",
sprintf(
"'/alignments/delete/%s'",
h($alignment['id'])
diff --git a/templates/element/genericElements/IndexTable/Fields/owner.php b/templates/element/genericElements/IndexTable/Fields/owner.php
index 17d491f..aa16e41 100644
--- a/templates/element/genericElements/IndexTable/Fields/owner.php
+++ b/templates/element/genericElements/IndexTable/Fields/owner.php
@@ -1,5 +1,5 @@
Hash->extract($row, $field['owner_type_path'])[0];
+ $type = $this->Hash->extract($row, $field['owner_model_path'])[0];
$owner = $row[$type];
$types = [
'individual' => [
diff --git a/templates/element/genericElements/IndexTable/Fields/user.php b/templates/element/genericElements/IndexTable/Fields/user.php
new file mode 100644
index 0000000..25504fc
--- /dev/null
+++ b/templates/element/genericElements/IndexTable/Fields/user.php
@@ -0,0 +1,11 @@
+Hash->extract($row, 'user.id')[0];
+ $userName = $this->Hash->extract($row, 'user.username')[0];
+ echo $this->Html->link(
+ h($userName),
+ ['controller' => 'users', 'action' => 'view', $userId]
+ );
+ }
+
+?>
diff --git a/templates/element/genericElements/ListTopBar/element_simple.php b/templates/element/genericElements/ListTopBar/element_simple.php
index 6747eb1..a14976f 100644
--- a/templates/element/genericElements/ListTopBar/element_simple.php
+++ b/templates/element/genericElements/ListTopBar/element_simple.php
@@ -71,12 +71,8 @@
\ No newline at end of file
diff --git a/templates/element/genericElements/ListTopBar/group_search.php b/templates/element/genericElements/ListTopBar/group_search.php
index 8e85f39..7822e07 100644
--- a/templates/element/genericElements/ListTopBar/group_search.php
+++ b/templates/element/genericElements/ListTopBar/group_search.php
@@ -12,6 +12,7 @@
* - id: element ID for the input field - defaults to quickFilterField
*/
if (!isset($data['requirement']) || $data['requirement']) {
+ $filterEffective = !empty($quickFilter); // No filters will be picked up, thus rendering the filtering useless
$filteringButton = '';
if (!empty($data['allowFilering'])) {
$activeFilters = !empty($activeFilters) ? $activeFilters : [];
@@ -32,9 +33,10 @@
$filteringButton = $this->Bootstrap->button($buttonConfig);
}
$button = empty($data['button']) && empty($data['fa-icon']) ? '' : sprintf(
- '%s
',
+ '%s
',
empty($data['data']) ? '' : h($data['data']),
h($tableRandomValue),
+ $filterEffective ? '' : 'disabled="disabled"',
empty($data['fa-icon']) ? '' : sprintf('', h($data['fa-icon'])),
empty($data['button']) ? '' : h($data['button']),
$filteringButton
@@ -43,13 +45,14 @@
$button .= $this->element('/genericElements/ListTopBar/element_simple', array('data' => $data['cancel']));
}
$input = sprintf(
- '',
+ '',
h($tableRandomValue),
empty($data['placeholder']) ? '' : h($data['placeholder']),
empty($data['placeholder']) ? '' : h($data['placeholder']),
empty($data['id']) ? 'quickFilterField' : h($data['id']),
empty($data['searchKey']) ? 'searchall' : h($data['searchKey']),
- empty($data['value']) ? (!empty($quickFilterValue) ? h($quickFilterValue) : '') : h($data['value'])
+ empty($data['value']) ? (!empty($quickFilterValue) ? h($quickFilterValue) : '') : h($data['value']),
+ $filterEffective ? '' : 'disabled="disabled"'
);
echo sprintf(
'%s%s
',
@@ -127,7 +130,8 @@
}
$searchType = $('')
.text(searchContain ? '= __('Contain') ?>' : '= __('Exact match') ?>')
- .attr('title', searchContain ? '= __('The search value will be used as a substring') ?>' : '= __('The search value must strictly match') ?>')
+ .attr('title', searchContain ? '= __('The search value can be used as a substring with the wildcard operator `%`') ?>' : '= __('The search value must strictly match') ?>')
+ .attr('style', 'cursor: help;')
tableData.push([fieldName, $searchType])
});
tableData.sort((a, b) => a[0] < b[0] ? -1 : 1)
@@ -144,11 +148,7 @@
}
function openFilteringModal(clicked, url, reloadUrl, tableId) {
- const loadingOverlay = new OverlayFactory(clicked);
- loadingOverlay.show()
- UI.openModalFromURL(url, reloadUrl, tableId).finally(() => {
- loadingOverlay.hide()
- })
+ UI.overlayUntilResolve(clicked, UI.submissionModalForIndex(url, reloadUrl, tableId))
}
});
diff --git a/templates/element/genericElements/ListTopBar/group_simple.php b/templates/element/genericElements/ListTopBar/group_simple.php
index 2c79909..187b616 100644
--- a/templates/element/genericElements/ListTopBar/group_simple.php
+++ b/templates/element/genericElements/ListTopBar/group_simple.php
@@ -5,7 +5,7 @@
$elements .= $this->element('/genericElements/ListTopBar/element_' . (empty($element['type']) ? 'simple' : h($element['type'])), array('data' => $element, 'tableRandomValue' => $tableRandomValue));
}
echo sprintf(
- '%s
',
+ '%s
',
(!empty($data['id'])) ? 'id="' . h($data['id']) . '"' : '',
$elements
);
diff --git a/templates/element/genericElements/SingleViews/Fields/alignmentField.php b/templates/element/genericElements/SingleViews/Fields/alignmentField.php
index eb922b9..50e9162 100644
--- a/templates/element/genericElements/SingleViews/Fields/alignmentField.php
+++ b/templates/element/genericElements/SingleViews/Fields/alignmentField.php
@@ -20,7 +20,7 @@ if ($field['scope'] === 'individuals') {
h($alignment['organisation']['name'])
),
sprintf(
- "UI.openModalFromURL(%s);",
+ "UI.submissionModalForSinglePage(%s);",
sprintf(
"'/alignments/delete/%s'",
$alignment['id']
@@ -40,7 +40,7 @@ if ($field['scope'] === 'individuals') {
h($alignment['individual']['email'])
),
sprintf(
- "UI.openModalFromURL(%s);",
+ "UI.submissionModalForSinglePage(%s);",
sprintf(
"'/alignments/delete/%s'",
$alignment['id']
@@ -53,7 +53,7 @@ echo sprintf(
'%s
',
$alignments,
sprintf(
- "UI.openModalFromURL('/alignments/add/%s/%s');",
+ "UI.submissionModalForSinglePage('/alignments/add/%s/%s');",
h($field['scope']),
h($extracted['id'])
),
diff --git a/templates/element/genericElements/side_menu_scaffold.php b/templates/element/genericElements/side_menu_scaffold.php
index bd6ab03..9e8eab5 100644
--- a/templates/element/genericElements/side_menu_scaffold.php
+++ b/templates/element/genericElements/side_menu_scaffold.php
@@ -35,7 +35,7 @@ if (isset($menu[$metaGroup])) {
}
$active = ($scope === $this->request->getParam('controller') && $action === $this->request->getParam('action'));
if (!empty($data['popup'])) {
- $link_template = '%s';
+ $link_template = '%s';
} else {
$link_template = '%s';
}
diff --git a/templates/genericTemplates/confirm.php b/templates/genericTemplates/confirm.php
index ea4c3b2..0d2fbd9 100644
--- a/templates/genericTemplates/confirm.php
+++ b/templates/genericTemplates/confirm.php
@@ -13,7 +13,7 @@
= $this->Form->postLink(
h($actionName),
$path,
- ['class' => 'btn btn-primary button-execute']
+ ['class' => 'btn btn-primary button-execute', 'id' => 'submitButton']
)
?>
diff --git a/templates/genericTemplates/delete.php b/templates/genericTemplates/delete.php
index 7da0be7..6b07d6a 100644
--- a/templates/genericTemplates/delete.php
+++ b/templates/genericTemplates/delete.php
@@ -1,7 +1,13 @@