PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / admin / layouts / operators / permissions.php

permissions.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/layouts/operators/permissions.php

532 lines 24.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - E4J srl
6 * @copyright Copyright (C) 2024 E4J srl. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 /**
14 * Obtain vars from arguments received in the layout file.
15 * It is possible to manage either all tool permissions for
16 * one operator, or the permissions of one tool for all operators.
17 * It is eventually allowed to manage one tool for one operator,
18 * but it is NOT possible to manage all tools for all operators.
19 *
20 * @var string $tool Optional tool type (i.e. "tableaux").
21 * @var int $operator_id Optional operator ID.
22 * @var string $toggle_event Optional JS event name to toggle the modal.
23 */
24 extract($displayData);
25
26 // define the tool to manage and/or the operator ID
27 $tool = $tool ?? null;
28 $operator_id = $operator_id ?? null;
29
30 // js event to toggle the modal window
31 $toggle_event = $toggle_event ?? 'vbo-tool-permissions-modal-toggle';
32 $loading_event = 'vbo-tool-permissions-modal-loading';
33 $dismiss_event = 'vbo-tool-permissions-modal-dismiss';
34
35 // language definitions
36 JText::script('VBOPERMSOPERATORS');
37 JText::script('VBO_WANT_PROCEED');
38 JText::script('VBSAVE');
39 JText::script('VBO_PLEASE_SELECT');
40
41 // access the global operators object
42 $oper_obj = VikBooking::getOperatorInstance();
43
44 // get the permission types for the request tool, or for all tools
45 $permission_types = $oper_obj->getToolPermissionTypes($tool);
46
47 if (!$permission_types || (!$tool && !$operator_id)) {
48 // invalid layout setup, abort
49 return;
50 }
51
52 if ($tool) {
53 // always convert the permission types into an associative list of tools-permissions
54 $permission_types = [$tool => $permission_types];
55 }
56
57 // check if we should load the details of one exact operator ID or all
58 $operator = [];
59 $operators_list = [];
60 $operators_assoc = [];
61
62 if ($operator_id) {
63 $operator = $oper_obj->getOne($operator_id);
64 if (!$operator) {
65 // abort
66 VBOHttpDocument::getInstance()->close(404, 'Operator not found');
67 }
68 } else {
69 // load all the operators
70 $operators_list = $oper_obj->getAll();
71 foreach ($operators_list as $operator_info) {
72 $operators_assoc[$operator_info['id']] = implode(' ', array_filter([$operator_info['first_name'], $operator_info['last_name']]));
73 }
74 }
75
76 ?>
77
78 <div class="vbo-operator-tool-permissions-container" style="display: none;">
79 <div class="vbo-operator-tool-permissions-wrap">
80 <div class="vbo-operator-tools-list">
81 <div class="vbo-operator-tool-tab vbo-operator-tool-tab-activeperms vbo-operator-tool-tab-active" data-tool-id="">
82 <span class="vbo-operator-tool-name"><?php echo JText::translate('VBO_ACTIVE_PERMS'); ?></span>
83 </div>
84 <?php
85 foreach ($permission_types as $tool_id => $tool_data) {
86 ?>
87 <div class="vbo-operator-tool-tab" data-tool-id="<?php echo JHtml::fetch('esc_attr', $tool_id); ?>">
88 <span class="vbo-operator-tool-name"><?php echo $tool_data['name']; ?></span>
89 </div>
90 <?php
91 }
92 ?>
93 </div>
94 <div class="vbo-operator-tools-permissions">
95 <div class="vbo-operator-tool-permissions vbo-operator-tool-permissions-activeperms" data-tool-id="">
96 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
97 <div class="vbo-params-wrap">
98 <div class="vbo-params-container">
99 <?php
100 if ($operator_id) {
101 // display the active permissions for the current operator
102 foreach ($operator['perms'] as $tool_perms) {
103 $tool_name = $oper_obj->getToolName($tool_perms['type']);
104 ?>
105 <div class="vbo-params-block">
106 <div class="vbo-param-container">
107 <div class="vbo-param-label">
108 <span class="label label-info"><?php echo $tool_name; ?></span>
109 </div>
110 <div class="vbo-param-setting">
111 <button type="button" class="btn vbo-tool-permissions-edit-btn" data-operator-id="<?php echo $operator['id']; ?>" data-tool-id="<?php echo $tool_perms['type']; ?>"><?php VikBookingIcons::e('edit'); ?> <?php echo JText::translate('VBMAINPAYMENTSEDIT'); ?></button>
112 <button type="button" class="btn btn-danger vbo-permissions-del-btn" data-operator-id="<?php echo $operator['id']; ?>" data-tool-id="<?php echo $tool_perms['type']; ?>"><?php VikBookingIcons::e('times'); ?> <?php echo JText::translate('VBELIMINA'); ?></button>
113 </div>
114 </div>
115 </div>
116 <?php
117 }
118 if (!$operator['perms']) {
119 ?>
120 <p class="info"><?php echo JText::translate('VBO_NO_RECORDS_FOUND'); ?></p>
121 <?php
122 }
123 } elseif ($tool) {
124 // display all operators with an active permission for this tool
125 $active_operators = $oper_obj->getOperatorsFromPermissions($tool, $operators_list);
126 foreach ($active_operators as $active_operator) {
127 $operator_tool_perms = json_encode($active_operator['perms']);
128 ?>
129 <div class="vbo-params-block">
130 <div class="vbo-param-container">
131 <div class="vbo-param-label">
132 <div class="vbo-customer-info-box">
133 <div class="vbo-customer-info-box-avatar vbo-customer-avatar-small">
134 <span>
135 <?php
136 if (!empty($active_operator['pic'])) {
137 ?>
138 <img class="no-click" src="<?php echo strpos($active_operator['pic'], 'http') === 0 ? $active_operator['pic'] : VBO_SITE_URI . 'resources/uploads/' . $active_operator['pic']; ?>" />
139 <?php
140 } else {
141 VikBookingIcons::e('user-circle');
142 }
143 ?>
144 </span>
145 </div>
146 <div class="vbo-customer-info-box-name">
147 <a href="index.php?option=com_vikbooking&task=editoperator&cid[]=<?php echo $active_operator['id']; ?>" target="_blank">
148 <?php echo implode(' ', array_filter([$active_operator['first_name'], $active_operator['last_name']])); ?>
149 </a>
150 </div>
151 </div>
152 </div>
153 <div class="vbo-param-setting">
154 <input type="hidden" class="vbo-operator-tool-permissions-json" value="<?php echo JHtml::fetch('esc_attr', $operator_tool_perms); ?>" />
155 <button type="button" class="btn vbo-oper-permissions-edit-btn" data-operator-id="<?php echo $active_operator['id']; ?>" data-tool-id="<?php echo $tool; ?>"><?php VikBookingIcons::e('edit'); ?> <?php echo JText::translate('VBMAINPAYMENTSEDIT'); ?></button>
156 <button type="button" class="btn btn-danger vbo-permissions-del-btn" data-operator-id="<?php echo $active_operator['id']; ?>" data-tool-id="<?php echo $tool; ?>"><?php VikBookingIcons::e('times'); ?> <?php echo JText::translate('VBELIMINA'); ?></button>
157 </div>
158 </div>
159 </div>
160 <?php
161 }
162 if (!$active_operators) {
163 ?>
164 <p class="<?php echo !$operators_list ? 'error' : 'info' ?>"><?php echo JText::translate('VBNOOPERATORS'); ?></p>
165 <?php
166 }
167 }
168 ?>
169 </div>
170 </div>
171 </div>
172 </div>
173 <?php
174 foreach ($permission_types as $tool_id => $tool_data) {
175 $tool_permissions = ($tool_data['permissions'] ?? []);
176 $tool_settings = [];
177 if ($tool) {
178 // in case of a single tool being rendered, push the (protected) parameter to choose the operator ID
179 $tool_permissions = array_merge([
180 '_operator_id' => [
181 'type' => 'select',
182 'label' => JText::translate('VBOOPERATOR'),
183 'help' => JText::translate('VBOADDOPERATORPERM'),
184 'assets' => true,
185 'asset_options' => [
186 'placeholder' => '',
187 'allowClear' => true,
188 ],
189 // do NOT merge or unshift to keep the associative list on numeric keys, use the array union operator instead!
190 'options' => (['' => ''] + $operators_assoc),
191 ],
192 ], $tool_permissions);
193 } elseif (($operator['perms'] ?? [])) {
194 // in case of a single operator and related tools being rendered, populate the existing permissions for each tool
195 foreach ($operator['perms'] as $tool_perms) {
196 if (!strcasecmp($tool_perms['type'], $tool_id)) {
197 // operator-tool permissions found
198 $tool_settings = $tool_perms['perms'] ?: [];
199 break;
200 }
201 }
202 }
203 ?>
204 <div class="vbo-operator-tool-permissions vbo-operator-tool-tab-selector" data-tool-id="<?php echo JHtml::fetch('esc_attr', $tool_id); ?>" style="display: none;">
205 <div class="vbo-admin-container vbo-admin-container-full vbo-admin-container-compact">
206 <div class="vbo-params-wrap">
207 <div class="vbo-params-container">
208 <?php echo VBOParamsRendering::getInstance($tool_permissions, $tool_settings)->setInputName('tool_perms[' . $tool_id . ']')->getHtml(); ?>
209 </div>
210 </div>
211 </div>
212
213 <?php
214 // if the current user does not have access to this tool, display a warning
215 if ($operator_id && !in_array($tool_id, array_column($operator['perms'], 'type'))): ?>
216 <p class="warn"><?php echo JText::translate('VBO_OPERATOR_NO_TOOL_PERMS'); ?></p>
217 <?php endif; ?>
218 </div>
219 <?php
220 }
221 ?>
222 </div>
223 </div>
224 </div>
225
226 <script type="text/javascript">
227 // save button handler
228 function vboHandleSaveToolPermissions(e) {
229 // disable the saving button
230 let button = e.target;
231 if (button.tagName.toLowerCase() === 'i') {
232 button = button.parentNode;
233 }
234 button.disabled = true;
235
236 // find the active tool-tab
237 let active_tab = document.querySelector('.vbo-operator-tool-tab.vbo-operator-tool-tab-active');
238
239 if (!active_tab) {
240 // enable the button
241 button.disabled = false;
242
243 // dismiss the modal
244 VBOCore.emitEvent('<?php echo $toggle_event; ?>');
245
246 // abort (nothing to save)
247 return false;
248 }
249
250 let tool_id = active_tab.getAttribute('data-tool-id');
251 let active_params = document.querySelector('.vbo-operator-tool-permissions[data-tool-id="' + (tool_id || '') + '"]');
252
253 if (!tool_id || !active_params) {
254 // enable the button
255 button.disabled = false;
256
257 // dismiss the modal
258 VBOCore.emitEvent('<?php echo $dismiss_event; ?>');
259
260 // abort (nothing to save)
261 return false;
262 }
263
264 // detect the saving mode, either one tool for various operators,
265 // or various tools for one operator, to match mandatory values.
266 let manage_mode = '<?php echo $tool ? 'tool_to_operators' : 'tools_to_operator'; ?>';
267 let operator_id = null;
268
269 if (manage_mode === 'tool_to_operators') {
270 // one tool for various operators
271
272 // make sure the operator ID param was selected
273 operator_id = active_params.querySelector('select[name="tool_perms[tableaux][_operator_id]"]')?.value;
274 if (!operator_id) {
275 // missing operator
276 alert(Joomla.JText._('VBO_PLEASE_SELECT'));
277
278 // enable the button
279 button.disabled = false;
280
281 // abort
282 return false;
283 }
284 } else {
285 // various tools for one operator
286 operator_id = '<?php echo $operator_id; ?>';
287 }
288
289 // build the request data object
290 let permsData = {};
291
292 // scan all permission params to collect the values
293 active_params.querySelectorAll('input, select, textarea').forEach((input_el) => {
294 // use a regex to get the proper input name, array values will be supported as long as the value is an array
295 let first_rx = new RegExp("^tool_perms\\[" + tool_id + "\\]\\[", 'g');
296 let input_name = input_el.getAttribute('name')?.replace(first_rx, '')?.replace(/\]?\[?\]$/, '');
297 if (!input_name || input_name === '_operator_id') {
298 // invalid or protected param field (i.e. select2 helper elements)
299 return;
300 }
301
302 // get the param value
303 let input_value = input_el.value;
304
305 // check if an array, only supported on multiple-select
306 if (input_el.tagName.toLowerCase() === 'select' && input_el.multiple) {
307 // start an array
308 input_value = [];
309 // scan all selected (use ":checked" pseudoselector) options
310 input_el.querySelectorAll('option:checked').forEach((opt) => {
311 input_value.push(opt.value);
312 });
313 }
314
315 // set request property and value
316 permsData[input_name] = input_value;
317 });
318
319 // start loading and make the request
320 VBOCore.emitEvent('<?php echo $loading_event; ?>');
321
322 VBOCore.doAjax(
323 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=operators.savePermission'); ?>",
324 {
325 operator_id: operator_id,
326 tool_id: tool_id,
327 perms: permsData,
328 tmpl: "component",
329 },
330 (response) => {
331 // stop loading
332 VBOCore.emitEvent('<?php echo $loading_event; ?>');
333
334 // dismiss the modal
335 VBOCore.emitEvent('<?php echo $dismiss_event; ?>');
336
337 // reload the current page
338 window.location.reload();
339 },
340 (error) => {
341 // display error
342 alert(error.responseText);
343
344 // stop loading
345 VBOCore.emitEvent('<?php echo $loading_event; ?>');
346
347 // enable the button
348 button.disabled = false;
349 }
350 );
351 }
352
353 jQuery(function() {
354
355 // handle tool tabs switching
356 jQuery('.vbo-operator-tool-tab').on('click', function(e) {
357 let tool_id = jQuery(this).attr('data-tool-id');
358 jQuery('.vbo-operator-tool-tab').removeClass('vbo-operator-tool-tab-active');
359 jQuery('.vbo-operator-tool-permissions').hide().removeClass('vbo-operator-tool-permissions-active');
360 jQuery(this).addClass('vbo-operator-tool-tab-active');
361 jQuery('.vbo-operator-tool-permissions[data-tool-id="' + tool_id + '"]').show().addClass('vbo-operator-tool-permissions-active');
362 if (tool_id && <?php echo $tool ? 'true' : 'false'; ?>) {
363 // when clicking a tool-tab during the tool permissions management, reset the current operator id and other fields
364 if (jQuery(e.target).hasClass('vbo-operator-tool-name')) {
365 // not a JS event triggered, but a real click on this tool-tab
366 let container = jQuery('.vbo-operator-tool-permissions[data-tool-id="' + tool_id + '"]');
367 container.find('select[name="tool_perms[' + tool_id + '][_operator_id]"]').find('option:checked').prop('selected', false);
368 container.find('select[name="tool_perms[' + tool_id + '][_operator_id]"]').trigger('change');
369 // reset additional fields
370 container.find('input, textarea').val('').trigger('change');
371 container.find('select[multiple]').find('option:checked').prop('selected', false);
372 container.find('select[multiple]').trigger('change');
373 }
374 }
375 });
376
377 // handle button to edit the tool permissions for a specific operator
378 jQuery('.vbo-oper-permissions-edit-btn').on('click', function() {
379 let operator_id = jQuery(this).attr('data-operator-id');
380 let tool_id = jQuery(this).attr('data-tool-id');
381 let oper_tool_perms_json = jQuery(this).parent().find('input.vbo-operator-tool-permissions-json').val();
382
383 if (!operator_id || !tool_id) {
384 return false;
385 }
386
387 // attempt to decode the current operator tool permissions
388 let oper_tool_perms = {};
389 try {
390 oper_tool_perms = oper_tool_perms_json ? JSON.parse(oper_tool_perms_json) : {};
391 } catch(err) {
392 oper_tool_perms = {};
393 console.error('could not parse JSON permissions', err, oper_tool_perms_json);
394 }
395
396 // scan all tool permission fields
397 document.querySelector('.vbo-operator-tool-permissions[data-tool-id="' + tool_id + '"]').querySelectorAll('input, select, textarea').forEach((input_el) => {
398 let first_rx = new RegExp("^tool_perms\\[" + tool_id + "\\]\\[", 'g');
399 let input_name = input_el.getAttribute('name')?.replace(first_rx, '')?.replace(/\]?\[?\]$/, '');
400
401 if (!input_name) {
402 // invalid param field (i.e. select2 helper elements)
403 return;
404 }
405
406 if (input_name === '_operator_id') {
407 // ensure to populate the operator ID
408 (input_el.querySelector('option[value="' + operator_id + '"]') || {}).selected = true;
409
410 // trigger the element change event
411 input_el.dispatchEvent(new Event('change'));
412
413 // parse next
414 return;
415 }
416
417 if (oper_tool_perms.hasOwnProperty(input_name)) {
418 if (Array.isArray(oper_tool_perms[input_name])) {
419 // multiple values
420 oper_tool_perms[input_name].forEach((cur_value) => {
421 (input_el.querySelector('option[value="' + cur_value + '"]') || {}).selected = true;
422 });
423 } else {
424 // single value
425 input_el.value = oper_tool_perms[input_name];
426 }
427 } else {
428 // reset this setting to the initial empty state
429
430 // check if an array, only supported on multiple-select
431 if (input_el.tagName.toLowerCase() === 'select' && input_el.multiple) {
432 // scan all selected (use ":checked" pseudoselector) options
433 input_el.querySelectorAll('option:checked').forEach((opt) => {
434 // un-select this option
435 opt.selected = false;
436 });
437 } else {
438 input_el.value = '';
439 }
440 }
441
442 // trigger the element change event
443 input_el.dispatchEvent(new Event('change'));
444 });
445
446 // trigger the event to open the requested tool tab
447 jQuery('.vbo-operator-tool-tab[data-tool-id="' + tool_id + '"]').trigger('click');
448 });
449
450 // handle button to edit the operator permissions for a specific tool
451 jQuery('.vbo-tool-permissions-edit-btn').on('click', function() {
452 let operator_id = jQuery(this).attr('data-operator-id');
453 let tool_id = jQuery(this).attr('data-tool-id');
454
455 // trigger the event to open the requested tool tab
456 jQuery('.vbo-operator-tool-tab[data-tool-id="' + tool_id + '"]').trigger('click');
457
458 // we do not really need to inject or populate the fields, because they must have been populated already
459 });
460
461 // handle button to remove an operator-tool-permission
462 jQuery('.vbo-permissions-del-btn').on('click', function() {
463 if (!confirm(Joomla.JText._('VBO_WANT_PROCEED'))) {
464 return false;
465 }
466
467 let operator_id = jQuery(this).attr('data-operator-id');
468 let tool_id = jQuery(this).attr('data-tool-id');
469
470 let element = jQuery(this).closest('.vbo-params-block');
471
472 // start loading and make the request
473 VBOCore.emitEvent('<?php echo $loading_event; ?>');
474
475 VBOCore.doAjax(
476 "<?php echo VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=operators.removePermission'); ?>",
477 {
478 operator_id: operator_id,
479 tool_id: tool_id,
480 tmpl: "component"
481 },
482 (response) => {
483 // stop loading
484 VBOCore.emitEvent('<?php echo $loading_event; ?>');
485
486 // delete the element from the DOM
487 element.remove();
488 },
489 (error) => {
490 console.error(error);
491 alert(error.responseText);
492 // stop loading
493 VBOCore.emitEvent('<?php echo $loading_event; ?>');
494 }
495 );
496 });
497
498 // build footer save button
499 const permissionsButtonSave = document.createElement('button');
500 permissionsButtonSave.classList.add('btn', 'btn-success');
501 permissionsButtonSave.setAttribute('type', 'button');
502 permissionsButtonSave.innerHTML = '<?php VikBookingIcons::e('save'); ?> ' + Joomla.JText._('VBSAVE');
503 permissionsButtonSave.addEventListener('click', vboHandleSaveToolPermissions);
504
505 // handle modal toggle (show/hide)
506 document.addEventListener('<?php echo $toggle_event; ?>', () => {
507 // always enable the footer saving button
508 permissionsButtonSave.disabled = false;
509
510 // render modal
511 let modalBody = VBOCore.displayModal({
512 suffix: 'operator_permissions_modal',
513 extra_class: 'vbo-modal-rounded vbo-modal-tall',
514 title: Joomla.JText._('VBOPERMSOPERATORS'),
515 body_prepend: true,
516 lock_scroll: true,
517 footer_right: permissionsButtonSave,
518 loading_event: '<?php echo $loading_event; ?>',
519 dismiss_event: '<?php echo $dismiss_event; ?>',
520 onDismiss: () => {
521 // move modal content back
522 jQuery('.vbo-operator-tool-permissions-wrap').appendTo(jQuery('.vbo-operator-tool-permissions-container'));
523 }
524 });
525
526 // set modal content
527 jQuery('.vbo-operator-tool-permissions-wrap').appendTo(modalBody);
528 });
529
530 });
531 </script>
532