chg: [requestProcessor] UI improvements and simplified creation of

processors
pull/41/head
mokaddem 2021-03-18 14:01:14 +01:00
parent 0a1294bbee
commit f3f73a475b
9 changed files with 161 additions and 93 deletions

View File

@ -8,7 +8,7 @@ interface GenericProcessorActionI
{ {
public function create($requestData); public function create($requestData);
public function process($requestID, $serverRequest); public function process($requestID, $serverRequest);
public function discard($requestID); public function discard($requestID ,$requestData);
public function setViewVariables($controller, $request); public function setViewVariables($controller, $request);
} }
@ -89,11 +89,6 @@ class GenericRequestProcessor
} }
} }
public function checkLoading()
{
return 'Assimilation successful!';
}
protected function setViewVariablesConfirmModal($controller, $id, $title='', $question='', $actionName='') protected function setViewVariablesConfirmModal($controller, $id, $title='', $question='', $actionName='')
{ {
$controller->set('title', !empty($title) ? $title : __('Process request {0}', $id)); $controller->set('title', !empty($title) ? $title : __('Process request {0}', $id));
@ -102,6 +97,63 @@ class GenericRequestProcessor
$controller->set('path', ['controller' => 'inbox', 'action' => 'process', $id]); $controller->set('path', ['controller' => 'inbox', 'action' => 'process', $id]);
} }
protected function genActionResult($data, $success, $message, $errors=[])
{
return [
'data' => $data,
'success' => $success,
'message' => $message,
'errors' => $errors,
];
}
public function genHTTPReply($controller, $processResult, $request, $redirect=null)
{
if (is_array($request)) {
$scope = $request['scope'];
$action = $request['action'];
} else {
$scope = $request->scope;
$action = $request->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) public function create($requestData)
{ {
$requestData['scope'] = $this->scope; $requestData['scope'] = $this->scope;
@ -109,17 +161,22 @@ class GenericRequestProcessor
$requestData['description'] = $this->description; $requestData['description'] = $this->description;
$request = $this->generateRequest($requestData); $request = $this->generateRequest($requestData);
$savedRequest = $this->Inbox->save($request); $savedRequest = $this->Inbox->save($request);
if ($savedRequest !== false) { return $this->genActionResult(
// log here $savedRequest,
} $savedRequest !== false,
__('{0} request for {1} created', $this->scope, $this->action),
$request->getErrors()
);
} }
public function discard($requestData) public function discard($id, $requestData)
{ {
$request = $this->generateRequest($requestData); $request = $this->Inbox->get($id);
$savedRequest = $this->Inbox->save($request); $this->Inbox->delete($request);
if ($savedRequest !== false) { return $this->genActionResult(
// log here [],
} true,
__('{0}.{1} request #{2} discarded', $this->scope, $this->action, $id)
);
} }
} }

View File

@ -18,7 +18,7 @@ class UserRequestProcessor extends GenericRequestProcessor
public function create($requestData) public function create($requestData)
{ {
parent::create($requestData); return parent::create($requestData);
} }
} }
@ -47,7 +47,7 @@ class RegistrationProcessor extends UserRequestProcessor implements GenericProce
public function create($requestData) { public function create($requestData) {
$this->validateRequestData($requestData); $this->validateRequestData($requestData);
$requestData['title'] = __('User account creation requested for {0}', $requestData['data']['email']); $requestData['title'] = __('User account creation requested for {0}', $requestData['data']['email']);
parent::create($requestData); return parent::create($requestData);
} }
public function setViewVariables($controller, $request) public function setViewVariables($controller, $request)
@ -77,39 +77,42 @@ class RegistrationProcessor extends UserRequestProcessor implements GenericProce
$controller->set(compact('dropdownData')); $controller->set(compact('dropdownData'));
} }
public function process($id, $serverRequest) public function process($id, $requestData)
{ {
$data = $serverRequest->getData(); if ($requestData['individual_id'] == -1) {
if ($data['individual_id'] == -1) {
$individual = $this->Users->Individuals->newEntity([ $individual = $this->Users->Individuals->newEntity([
'uuid' => $data['uuid'], 'uuid' => $requestData['uuid'],
'email' => $data['email'], 'email' => $requestData['email'],
'first_name' => $data['first_name'], 'first_name' => $requestData['first_name'],
'last_name' => $data['last_name'], 'last_name' => $requestData['last_name'],
'position' => $data['position'], 'position' => $requestData['position'],
]); ]);
$individual = $this->Users->Individuals->save($individual); $individual = $this->Users->Individuals->save($individual);
} else { } else {
$individual = $this->Users->Individuals->get($data['individual_id']); $individual = $this->Users->Individuals->get($requestData['individual_id']);
} }
$user = $this->Users->newEntity([ $user = $this->Users->newEntity([
'individual_id' => $individual->id, 'individual_id' => $individual->id,
'username' => $data['username'], 'username' => $requestData['username'],
'password' => '~PASSWORD_TO_BE_REPLACED~', 'password' => '~PASSWORD_TO_BE_REPLACED~',
'role_id' => $data['role_id'], 'role_id' => $requestData['role_id'],
'disabled' => $data['disabled'], 'disabled' => $requestData['disabled'],
]); ]);
$user = $this->Users->save($user); $user = $this->Users->save($user);
return [
'data' => $user, if ($user !== false) {
'success' => $user !== false, $this->discard($id, $requestData);
'message' => $user !== false ? __('User `{0}` created', $user->username) : __('Could not create user `{0}`.', $user->username), }
'errors' => $user->getErrors() 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) public function discard($id, $requestData)
{ {
parent::discard($id); return parent::discard($id, $requestData);
} }
} }

View File

@ -59,6 +59,13 @@ class InboxController extends AppController
public function delete($id) 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, $request);
}
$this->set('deletionTitle', __('Discard request')); $this->set('deletionTitle', __('Discard request'));
$this->set('deletionText', __('Are you sure you want to discard request #{0}?', $id)); $this->set('deletionText', __('Are you sure you want to discard request #{0}?', $id));
$this->set('deletionConfirm', __('Discard')); $this->set('deletionConfirm', __('Discard'));
@ -75,17 +82,10 @@ class InboxController extends AppController
$scope = $request->scope; $scope = $request->scope;
$action = $request->action; $action = $request->action;
$this->requestProcessor = TableRegistry::getTableLocator()->get('RequestProcessor'); $this->requestProcessor = TableRegistry::getTableLocator()->get('RequestProcessor');
$processor = $this->requestProcessor->getProcessor($scope, $action); $processor = $this->requestProcessor->getProcessor($request->scope, $request->action);
if ($this->request->is('post')) { if ($this->request->is('post')) {
$processResult = $processor->process($id, $this->request); $processResult = $processor->process($id, $this->request->getData());
if ($processResult['success']) { return $processor->genHTTPReply($this, $processResult, $request);
$message = !empty($processResult['message']) ? $processResult['message'] : __('Request {0} processed.', $id);
$response = $this->RestResponse->ajaxSuccessResponse('RequestProcessor', "{$scope}.{$action}", $processResult['data'], $message);
} else {
$message = !empty($processResult['message']) ? $processResult['message'] : __('Request {0} could not be processed.', $id);
$response = $this->RestResponse->ajaxFailResponse('RequestProcessor', "{$scope}.{$action}", $processResult['data'], $message, $processResult['errors']);
}
return $response;
} else { } else {
$this->requestProcessor->render($this, $processor, $request); $this->requestProcessor->render($this, $processor, $request);
} }

View File

@ -150,8 +150,7 @@ class UsersController extends AppController
'last_name' => 'bar', 'last_name' => 'bar',
], ],
]; ];
$processor->create($data); $processorResult = $processor->create($data);
$this->Flash->success(__('Entry created')); return $processor->genHTTPReply($this, $processorResult, ['scope' => 'User', 'action' => 'Registration'], ['controller' => 'Inbox', 'action' => 'index']);
return $this->redirect(['controller' => 'Inbox', 'action' => 'index']);
} }
} }

View File

@ -721,7 +721,7 @@ class BoostrapModal extends BootstrapGeneric {
'footerClass' => [''], 'footerClass' => [''],
'type' => 'ok-only', 'type' => 'ok-only',
'variant' => '', 'variant' => '',
'confirmFunction' => '', 'confirmFunction' => '', // Will be called with the following arguments confirmFunction(modalObject, tmpApi)
'cancelFunction' => '' 'cancelFunction' => ''
]; ];
@ -847,10 +847,10 @@ class BoostrapModal extends BootstrapGeneric {
$buttonConfirm = (new BoostrapButton([ $buttonConfirm = (new BoostrapButton([
'variant' => $variant, 'variant' => $variant,
'text' => h($this->options['confirmText']), 'text' => h($this->options['confirmText']),
'class' => 'modal-confirm-button',
'params' => [ 'params' => [
'data-dismiss' => $this->options['confirmFunction'] ? '' : 'modal', 'data-dismiss' => $this->options['confirmFunction'] ? '' : 'modal',
// 'onclick' => sprintf('(function(clicked) { %s.finally( () => { $(clicked).closest(\'.modal\').data(\'modalObject\').hide() }) }(this))', $this->options['confirmFunction']) 'data-confirmFunction' => sprintf('%s', $this->options['confirmFunction'])
'onclick' => sprintf('closeModalOnFunctionCompletion(this, function(clicked) { return %s })', $this->options['confirmFunction'])
] ]
]))->button(); ]))->button();
return $buttonCancel . $buttonConfirm; return $buttonCancel . $buttonConfirm;

View File

@ -77,17 +77,20 @@ echo $this->element('genericElements/IndexTable/index_table', [
[ [
'url' => '/inbox/view', 'url' => '/inbox/view',
'url_params_data_paths' => ['id'], 'url_params_data_paths' => ['id'],
'icon' => 'eye' 'icon' => 'eye',
'title' => __('View request')
], ],
[ [
'open_modal' => '/inbox/process/[onclick_params_data_path]', 'open_modal' => '/inbox/process/[onclick_params_data_path]',
'modal_params_data_path' => 'id', 'modal_params_data_path' => 'id',
'icon' => 'cogs' 'icon' => 'cogs',
'title' => __('Process request')
], ],
[ [
'open_modal' => '/inbox/delete/[onclick_params_data_path]', 'open_modal' => '/inbox/delete/[onclick_params_data_path]',
'modal_params_data_path' => 'id', 'modal_params_data_path' => 'id',
'icon' => 'trash' 'icon' => 'trash',
'title' => __('Discard request')
], ],
] ]
] ]

View File

@ -81,17 +81,14 @@
$formIndividual $formIndividual
), ),
'confirmText' => __('Create user'), 'confirmText' => __('Create user'),
'confirmFunction' => 'submitRegistration(clicked)' 'confirmFunction' => 'submitRegistration'
]); ]);
?> ?>
</div> </div>
<script> <script>
function submitRegistration(clicked) { function submitRegistration(modalObject, tmpApi) {
const tmpApi = new AJAXApi({ const $forms = modalObject.$modal.find('form')
statusNode: clicked
})
const $forms = $(clicked).closest('.modal').find('form')
const url = $forms[0].action const url = $forms[0].action
const data1 = getFormData($forms[0]) const data1 = getFormData($forms[0])
const data2 = getFormData($forms[1]) const data2 = getFormData($forms[1])

View File

@ -688,8 +688,11 @@ class ModalFactory {
} }
/** Attach the submission click listener for modals that have been generated by raw HTML */ /** Attach the submission click listener for modals that have been generated by raw HTML */
findSubmitButtonAndAddListener(clearOnclick=true) { findSubmitButtonAndAddListener() {
const $submitButton = this.$modal.find('.modal-footer #submitButton') let $submitButton = this.$modal.find('.modal-footer #submitButton')
if (!$submitButton[0]) {
$submitButton = this.$modal.find('.modal-footer .modal-confirm-button')
}
if ($submitButton[0]) { if ($submitButton[0]) {
const formID = $submitButton.data('form-id') const formID = $submitButton.data('form-id')
let $form let $form
@ -698,26 +701,43 @@ class ModalFactory {
} else { } else {
$form = this.$modal.find('form') $form = this.$modal.find('form')
} }
if (clearOnclick) { if ($submitButton.data('confirmfunction') !== undefined && $submitButton.data('confirmfunction') !== '') {
const clickHandler = window[$submitButton.data('confirmfunction')]
this.options.APIConfirm = (tmpApi) => {
return clickHandler(this, tmpApi)
.then((data) => {
if (data.success) {
this.options.POSTSuccessCallback(data)
} else { // Validation error
this.injectFormValidationFeedback(form, data.errors)
return Promise.reject('Validation error');
}
})
.catch((errorMessage) => {
this.options.POSTFailCallback(errorMessage)
return Promise.reject(errorMessage);
})
}
} else {
$submitButton[0].removeAttribute('onclick') $submitButton[0].removeAttribute('onclick')
} this.options.APIConfirm = (tmpApi) => {
return tmpApi.postForm($form[0])
this.options.APIConfirm = (tmpApi) => { .then((data) => {
return tmpApi.postForm($form[0]) if (data.success) {
.then((data) => { this.options.POSTSuccessCallback(data)
if (data.success) { } else { // Validation error
this.options.POSTSuccessCallback(data) this.injectFormValidationFeedback(form, data.errors)
} else { // Validation error return Promise.reject('Validation error');
this.injectFormValidationFeedback(form, data.errors) }
return Promise.reject('Validation error'); })
} .catch((errorMessage) => {
}) this.options.POSTFailCallback(errorMessage)
.catch((errorMessage) => { return Promise.reject(errorMessage);
this.options.POSTFailCallback(errorMessage) })
return Promise.reject(errorMessage); }
})
} }
$submitButton.click(this.getConfirmationHandlerFunction()) $submitButton.click(this.getConfirmationHandlerFunction())
} }
} }
} }

View File

@ -66,17 +66,6 @@ function attachTestConnectionResultHtml(result, $container) {
return $testResultDiv return $testResultDiv
} }
function closeModalOnFunctionCompletion(clicked, fun) {
const result = fun(clicked)
if (result === undefined) {
$(clicked).closest('.modal').data('modalObject').hide()
} else {
result.finally( () => {
$(clicked).closest('.modal').data('modalObject').hide()
})
}
}
var UI var UI
$(document).ready(() => { $(document).ready(() => {
if (typeof UIFactory !== "undefined") { if (typeof UIFactory !== "undefined") {