PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.13
VikBooking Hotel Booking Engine & PMS v1.8.13
1.8.16 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 All 37 releases
vikbooking / site / helpers / operator.php

operator.php in VikBooking Hotel Booking Engine & PMS 1.8.13, at site/helpers/operator.php

678 lines 18.9 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 - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. 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 * Operator and tool permission types class handler.
15 *
16 * @since 1.11 (J) - 1.1 (WP)
17 */
18 final class VikBookingOperator
19 {
20 /**
21 * The singleton instance of the class.
22 *
23 * @var VikBookingOperator
24 */
25 protected static $instance = null;
26
27 /**
28 * A cache array holding all the existing operators.
29 *
30 * @var array[]
31 * @since 1.18.0 (J) - 1.8.0 (WP)
32 */
33 protected $operators = null;
34
35 /**
36 * The various tool permission types.
37 *
38 * @var array
39 *
40 * @since 1.16.9 (J) - 1.6.9 (WP)
41 */
42 protected $toolPermissionTypes = [];
43
44 /**
45 * Class constructor is protected.
46 *
47 * @see getInstance()
48 */
49 protected function __construct()
50 {
51 // load all the operator tools and related permission types
52 $this->loadToolPermissionTypes();
53 }
54
55 /**
56 * Returns the global VikBookingOperator object, either
57 * a new instance or the existing instance
58 * if the class was already instantiated.
59 *
60 * @return self A new instance of the class.
61 */
62 public static function getInstance()
63 {
64 if (is_null(static::$instance)) {
65 static::$instance = new static();
66 }
67
68 return static::$instance;
69 }
70
71 /**
72 * Returns the list of all the operators.
73 *
74 * @param array $ids Optional list of IDs to filter.
75 *
76 * @return array The list of operators
77 *
78 * @since 1.18.0 (J) - 1.8.0 (WP) The method now caches all the operators to prevent duplicate queries.
79 */
80 public function getAll(array $ids = [])
81 {
82 $dbo = JFactory::getDbo();
83
84 if (is_null($this->operators)) {
85 $this->operators = [];
86
87 $q = $dbo->getQuery(true)
88 ->select('*')
89 ->from($dbo->qn('#__vikbooking_operators'))
90 ->order($dbo->qn('first_name') . ' ASC')
91 ->order($dbo->qn('last_name') . ' ASC');
92
93 $dbo->setQuery($q);
94
95 foreach ($dbo->loadAssocList() as $o) {
96 $this->operators[$o['id']] = $o;
97 }
98 }
99
100 // take only the operators matching the specified query
101 return array_filter($this->operators, function($o) use ($ids) {
102 return !$ids || in_array($o['id'], $ids);
103 });
104 }
105
106 /**
107 * Fetches the information and permissions of one operator by ID.
108 *
109 * @param int $id The operator ID.
110 *
111 * @return array
112 */
113 public function getOne($id)
114 {
115 $dbo = JFactory::getDbo();
116
117 $dbo->setQuery(
118 $dbo->getQuery(true)
119 ->select('*')
120 ->from($dbo->qn('#__vikbooking_operators'))
121 ->where($dbo->qn('id') . ' = ' . (int) $id)
122 );
123
124 $operator = $dbo->loadAssoc();
125
126 if (!$operator) {
127 return [];
128 }
129
130 $operator['perms'] = !empty($operator['perms']) ? (array) json_decode($operator['perms'], true) : [];
131 $operator['work_days_week'] = !empty($operator['work_days_week']) ? (array) json_decode($operator['work_days_week'], true) : [];
132 $operator['work_days_exceptions'] = !empty($operator['work_days_exceptions']) ? (array) json_decode($operator['work_days_exceptions'], true) : [];
133
134 return $operator;
135 }
136
137 /**
138 * Returns a list of operators compatible for rendering them as elements.
139 *
140 * @param array $ids Optional list of IDs to filter.
141 *
142 * @return array
143 *
144 * @since 1.18.0 (J) - 1.8.0 (WP)
145 */
146 public function getElements(array $ids = [])
147 {
148 $elements = [];
149
150 foreach ($this->getAll($ids) as $operator) {
151 // check for operator's avatar picture
152 $operator_pic = $operator['pic'] ?: '';
153 if ($operator_pic) {
154 $operator_pic = strpos($operator_pic, 'http') === 0 ? $operator_pic : VBO_SITE_URI . 'resources/uploads/' . $operator_pic;
155 }
156
157 // push operator element
158 $elements[] = [
159 'id' => $operator['id'],
160 'name' => ltrim($operator['first_name'] . ' ' . $operator['last_name']),
161 'img_uri' => $operator_pic,
162 ];
163 }
164
165 return $elements;
166 }
167
168 /**
169 * Returns the list of all the operators filtered by a specific
170 * permission type and with an array of their own permissions.
171 *
172 * @param string $permtype The type of permission to look for.
173 * @param array $operators The list of operators.
174 *
175 * @return array The list of operators.
176 */
177 public function getOperatorsFromPermissions($permtype = '', $operators = [])
178 {
179 if (!$operators) {
180 $operators = $this->getAll();
181 }
182
183 foreach ($operators as $k => $v) {
184 $perms = !empty($v['perms']) && is_string($v['perms']) ? (array) json_decode($v['perms'], true) : [];
185 $operators[$k]['perms'] = $perms;
186 $enabled = false;
187 foreach ($perms as $perm) {
188 if ($permtype && ($perm['type'] ?? '') == $permtype) {
189 // turn the permissions into an associative array for just the requested tool
190 $operators[$k]['perms'] = $perm['perms'];
191 $enabled = true;
192 break;
193 }
194 }
195 if (!$enabled) {
196 unset($operators[$k]);
197 }
198 }
199
200 return array_values($operators);
201 }
202
203 /**
204 * Tells whether the operator is logged in by renewing
205 * the session cookie if the auth method is through code.
206 * Returns the information of the logged in operator or false.
207 *
208 * @return mixed Array if the operator is logged in, false otherwise.
209 */
210 public function getOperatorAccount()
211 {
212 $dbo = JFactory::getDbo();
213 $user = JFactory::getUser();
214
215 /**
216 * Beware of a possible magic method __get() in JUser.
217 * Assign the id property to a variable for evaluation.
218 */
219 $ujid = $user->id;
220
221 if (!$user->guest && !empty($ujid)) {
222 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `ujid`=".(int)$user->id." LIMIT 1;";
223 $dbo->setQuery($q);
224 $record = $dbo->loadAssoc();
225 if ($record) {
226 // user is logged in to the site account
227 return $record;
228 }
229 }
230
231 $session = JFactory::getSession();
232 $sessval = $session->get('vboOpFngpt', '');
233 $cookie = JFactory::getApplication()->input->cookie;
234 $cksess = $cookie->get('vboOpFngpt', '', 'string');
235
236 if (!empty($sessval)) {
237 // look up for this fingerprint in the session
238 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `fingpt`=" . $dbo->q($sessval);
239 $dbo->setQuery($q, 0, 1);
240 $record = $dbo->loadAssoc();
241 if ($record) {
242 // user is logged in through the session
243 return $record;
244 }
245 }
246
247 if (!empty($cksess)) {
248 // look up for this fingerprint in the cookie
249 $q = "SELECT * FROM `#__vikbooking_operators` WHERE `fingpt`=" . $dbo->q($cksess);
250 $dbo->setQuery($q, 0, 1);
251 $record = $dbo->loadAssoc();
252 if ($record) {
253 // user is logged in through the cookie, renew it for 2 weeks before returning the array
254 VikRequest::setCookie('vboOpFngpt', $cksess, (time() + (86400 * 14)), '/', '', false, true);
255 return $record;
256 }
257 }
258
259 // user is not logged in
260 return false;
261 }
262
263 /**
264 * Login request through the authentication code.
265 * If code is valid, the session and cookie are set.
266 *
267 * @param string $code the authentication code to check
268 *
269 * @return boolean true if the code exists, false otherwise
270 */
271 public function authOperator($code)
272 {
273 if (empty($code)) {
274 return false;
275 }
276
277 $dbo = JFactory::getDbo();
278 $session = JFactory::getSession();
279 $cookie = JFactory::getApplication()->input->cookie;
280
281 /**
282 * The operators authentication process is now case sensitive.
283 *
284 * @since 1.18 (J) - 1.8 (WP)
285 */
286 $q = "SELECT * FROM `#__vikbooking_operators` WHERE BINARY `code` = " . $dbo->q($code);
287 $dbo->setQuery($q, 0, 1);
288 $operator = $dbo->loadAssoc();
289
290 // ensure a valid code was provided
291 if ($operator) {
292 // send cookie
293 VikRequest::setCookie('vboOpFngpt', $operator['fingpt'], (time() + (86400 * 14)), '/', '', false, true);
294
295 // update session value
296 $session->set('vboOpFngpt', $operator['fingpt']);
297
298 return true;
299 }
300
301 // invalid code provided
302 return false;
303 }
304
305 /**
306 * Unsets the session value and sends an expired cookie.
307 * This action completely logs out an operator that should log back in.
308 *
309 * @return void
310 */
311 public function logoutOperator()
312 {
313 $app = JFactory::getApplication();
314 $session = JFactory::getSession();
315 $cookie = $app->input->cookie;
316
317 $session->set('vboOpFngpt', '');
318 VikRequest::setCookie('vboOpFngpt', $operator['fingpt'], (time() - (86400 * 14)), '/', '', false, true);
319
320 // logout from the site
321 $app->logout(JFactory::getUser()->id);
322 }
323
324 /**
325 * Checks whether the given operator has the permissions to access
326 * the given view type (permission type). Permissions are converted
327 * into an array if still JSON encoded, and updated via reference.
328 *
329 * @param array $operator the operator record
330 * @param string $permtype the name of the view to access
331 *
332 * @return boolean
333 */
334 public function checkPermissions(&$operator, $permtype)
335 {
336 if (!is_array($operator) || !$operator || empty($operator['perms'])) {
337 return false;
338 }
339
340 if (is_scalar($operator['perms'])) {
341 $operator['perms'] = json_decode($operator['perms'], true);
342 $operator['perms'] = is_array($operator['perms']) ? $operator['perms'] : [];
343 }
344
345 foreach ($operator['perms'] as $k => $perm) {
346 if (isset($perm['type']) && $perm['type'] == $permtype) {
347 // has permission for this View, take only these perms
348 $operator['perms'] = $operator['perms'][$k]['perms'];
349 return true;
350 }
351 }
352
353 // permission not found
354 return false;
355 }
356
357 /**
358 * Builds the URI to render the provided operator tool.
359 *
360 * @param string $tool The operator tool identifier.
361 * @param int $itemid The optional page/item ID.
362 *
363 * @return string The routed operator tool URI.
364 *
365 * @since 1.17.6 (WP) - 1.7.6 (WP)
366 */
367 public function getToolUri(string $tool, int $itemid = 0)
368 {
369 // build URI to current tool
370 return JRoute::rewrite(
371 sprintf(
372 'index.php?option=com_vikbooking&view=operators&tool=%s&Itemid=%d',
373 $tool,
374 ($itemid ?: JFactory::getApplication()->input->getInt('Itemid', 0))
375 )
376 );
377 }
378
379 /**
380 * Authorizes the currently logged operator to access the given tool.
381 *
382 * @param string $tool The operator tool identifier.
383 *
384 * @return array List of operator-tool data including:
385 * - The operator record accessing the tool.
386 * - The operator-tool permissions registry.
387 * - The base URI for rendering the tool.
388 *
389 * @throws Exception
390 *
391 * @since 1.17.6 (WP) - 1.7.6 (WP)
392 */
393 public function authOperatorToolData(string $tool)
394 {
395 // attempt to get the current operator
396 $operator = $this->getOperatorAccount();
397
398 if (!$operator) {
399 throw new Exception('Operator authentication required.', 401);
400 }
401
402 // get tool data
403 $tool_data = $this->getToolData($tool);
404
405 if (!$tool_data) {
406 // tool is unknown
407 throw new Exception(sprintf('Operator tool not found (%s)', $tool), 404);
408 }
409
410 if (!$this->checkPermissions($operator, $tool)) {
411 // no permission to access this tool
412 throw new Exception(sprintf('Not enough permissions to access the tool (%s)', $tool), 403);
413 }
414
415 return [
416 $operator,
417 new JObject(($operator['perms'] ?: [])),
418 $this->getToolUri($tool),
419 ];
420 }
421
422 /**
423 * Returns the data for the given tool identifier.
424 *
425 * @param string $tool The tool identifier.
426 *
427 * @return array
428 *
429 * @since 1.16.9 (J) - 1.6.9 (WP)
430 */
431 public function getToolData($tool)
432 {
433 return $this->toolPermissionTypes[$tool] ?? [];
434 }
435
436 /**
437 * Returns the name for the given tool identifier.
438 * If a raw language constant is detected, the raw
439 * tool identifier value is returned (front-end).
440 *
441 * @param string $tool The tool identifier.
442 *
443 * @return string
444 *
445 * @since 1.16.9 (J) - 1.6.9 (WP)
446 */
447 public function getToolName($tool)
448 {
449 $tool_name = $this->toolPermissionTypes[$tool]['name'] ?? $tool;
450
451 return preg_match("/^VB[A-Z0-9_]+$/", $tool_name) ? ucfirst(str_replace('_', ' ', $tool)) : $tool_name;
452 }
453
454 /**
455 * Returns a list of permission types for a specific tool (i.e. "tableaux") or all tools.
456 * Allows third-party plugins to define their own tool permission types.
457 *
458 * @param string $tool the tool identifier.
459 *
460 * @return array
461 *
462 * @since 1.16.9 (J) - 1.6.9 (WP)
463 */
464 public function getToolPermissionTypes($tool = null)
465 {
466 $default_tool_perms = $this->loadToolPermissionTypes();
467
468 if (!$tool) {
469 return $default_tool_perms;
470 }
471
472 return $default_tool_perms[$tool] ?? [];
473 }
474
475 /**
476 * Renders a native operator tool through a callback (i.e. "finance").
477 * Alternatively, tools could be rendered through a View (i.e. "tableaux").
478 * Lastly, third-party plugins could load their own operator tools.
479 *
480 * @param string $tool the tool identifier.
481 * @param array $operator the operator record calling the tool.
482 * @param object $permissinos the operator-tool permissions registry.
483 * @param string $tool_uri the base URI to the given tool.
484 *
485 * @return void
486 *
487 * @since 1.16.9 (J) - 1.6.9 (WP)
488 */
489 public function renderNativeToolLayout($tool, $operator, $permissions, $tool_uri)
490 {
491 // prepare the layout data
492 $layout_data = [
493 'tool' => $tool,
494 'operator' => $operator,
495 'permissions' => $permissions,
496 'tool_uri' => $tool_uri,
497 ];
498
499 // render the requested tool layout
500 echo JLayoutHelper::render('tools.' . $tool, $layout_data, null, [
501 'component' => 'com_vikbooking',
502 'client' => 'site',
503 ]);
504 }
505
506 /**
507 * Loads a list of default permission types for all the available tools.
508 * Allows third-party plugins to define their own tools and permission types.
509 *
510 * @return array
511 *
512 * @since 1.16.9 (J) - 1.6.9 (WP)
513 */
514 protected function loadToolPermissionTypes()
515 {
516 if ($this->toolPermissionTypes) {
517 // return the cached list
518 return $this->toolPermissionTypes;
519 }
520
521 // build the default tool permission types
522 $this->toolPermissionTypes = [
523 'tableaux' => [
524 'name' => JText::translate('VBOOPERPERMTABLEAUX'),
525 'icon' => '<i class="' . VikBookingIcons::i('stream') . '"></i>',
526 'permissions' => [
527 'days' => [
528 'type' => 'number',
529 'label' => JText::translate('VBOPERMTBLXDAYS'),
530 'help' => JText::translate('VBO_PERM_NEGATIVE_DAYS'),
531 'step' => 1,
532 'min' => -365,
533 'max' => 365,
534 'default' => 14,
535 ],
536 'rooms' => [
537 'type' => 'listings',
538 'label' => JText::translate('VBOPERMTBLXROOMS'),
539 'multiple' => true,
540 'asset_options' => [
541 'placeholder' => JText::translate('VBCOUPONALLVEHICLES'),
542 'allowClear' => true,
543 ],
544 ],
545 'guestname' => [
546 'type' => 'select',
547 'label' => JText::translate('VBOCUSTOMERDETAILS'),
548 'options' => [
549 1 => JText::translate('VBYES'),
550 0 => JText::translate('VBNO'),
551 ],
552 ],
553 'guestphone' => [
554 'type' => 'select',
555 'label' => JText::translate('ORDER_PHONE'),
556 'default' => 0,
557 'options' => [
558 1 => JText::translate('VBYES'),
559 0 => JText::translate('VBNO'),
560 ],
561 ],
562 'roomextras' => [
563 'type' => 'select',
564 'label' => JText::translate('VBPEDITBUSYEXTRACOSTS'),
565 'options' => [
566 1 => JText::translate('VBYES'),
567 0 => JText::translate('VBNO'),
568 ],
569 ],
570 ],
571 // this native tool is rendered through a View
572 'rendering_type' => 'view',
573 ],
574 'finance' => [
575 'name' => JText::translate('VBO_W_FINANCE_TITLE'),
576 'icon' => '<i class="' . VikBookingIcons::i('piggy-bank') . '"></i>',
577 'permissions' => [
578 'rooms' => [
579 'type' => 'listings',
580 'label' => JText::translate('VBOPERMTBLXROOMS'),
581 'multiple' => true,
582 'asset_options' => [
583 'placeholder' => JText::translate('VBCOUPONALLVEHICLES'),
584 'allowClear' => true,
585 ],
586 ],
587 ],
588 // this native tool is rendered through a layout thanks to a callback
589 'rendering_type' => 'layout',
590 'rendering_callback' => function ($tool, $operator, $permissions, $tool_uri) {
591 VikBooking::getOperatorInstance()->renderNativeToolLayout($tool, $operator, $permissions, $tool_uri);
592 },
593 ],
594 'guest_messaging' => [
595 'name' => JText::translate('VBO_W_GUESTMESSAGES_TITLE'),
596 'icon' => '<i class="' . VikBookingIcons::i('comment-dots') . '"></i>',
597 'permissions' => [
598 'rooms' => [
599 'type' => 'listings',
600 'label' => JText::translate('VBOPERMTBLXROOMS'),
601 'multiple' => true,
602 'asset_options' => [
603 'placeholder' => JText::translate('VBCOUPONALLVEHICLES'),
604 'allowClear' => true,
605 ],
606 ],
607 ],
608 // this native tool is rendered through a layout thanks to a callback
609 'rendering_type' => 'layout',
610 'rendering_callback' => function ($tool, $operator, $permissions, $tool_uri) {
611 VikBooking::getOperatorInstance()->renderNativeToolLayout($tool, $operator, $permissions, $tool_uri);
612 },
613 ],
614 'task_manager' => [
615 'name' => JText::translate('VBO_TASK_MANAGER'),
616 'icon' => '<i class="' . VikBookingIcons::i('tasks') . '"></i>',
617 'permissions' => [
618 'accept_tasks' => [
619 'type' => 'select',
620 'label' => JText::translate('VBO_ACCEPT_TASKS'),
621 'options' => [
622 1 => JText::translate('VBYES'),
623 0 => JText::translate('VBNO'),
624 ],
625 ],
626 ],
627 // this native tool is rendered through a layout thanks to a callback
628 'rendering_type' => 'layout',
629 'rendering_callback' => function ($tool, $operator, $permissions, $tool_uri) {
630 VikBooking::getOperatorInstance()->renderNativeToolLayout($tool, $operator, $permissions, $tool_uri);
631 },
632 ],
633 'work_days' => [
634 'name' => JText::translate('VBO_WORK_DAYS'),
635 'icon' => '<i class="' . VikBookingIcons::i('toolbox') . '"></i>',
636 'permissions' => [
637 'work_days_exceptions' => [
638 'type' => 'select',
639 'label' => JText::translate('VBO_EXCEPTIONS'),
640 'help' => implode(' - ', [JText::translate('VBO_WORK_DAYS_OFF'), JText::translate('VBO_WORK_DAYS_ON')]),
641 'options' => [
642 1 => JText::translate('VBYES'),
643 0 => JText::translate('VBNO'),
644 ],
645 ],
646 ],
647 // this native tool is rendered through a layout thanks to a callback
648 'rendering_type' => 'layout',
649 'rendering_callback' => function ($tool, $operator, $permissions, $tool_uri) {
650 VikBooking::getOperatorInstance()->renderNativeToolLayout($tool, $operator, $permissions, $tool_uri);
651 },
652 ],
653 ];
654
655 /**
656 * Trigger event to let other plugins register additional tools and permissions.
657 * Custom operator tools do NOT need to define a rendering type or callback.
658 *
659 * @return array A list of custom tools and related permission types.
660 */
661 $custom_tools = VBOFactory::getPlatform()->getDispatcher()->filter('onLoadOperatorToolPermissionTypes');
662
663 foreach ($custom_tools as $tool) {
664 if (!is_array($tool)) {
665 continue;
666 }
667 foreach ($tool as $tool_name => $tool_perms) {
668 if (!is_numeric($tool_name) && is_array($tool_perms)) {
669 // set valid tool, by also allowing to overwrite the default ones
670 $this->toolPermissionTypes[$tool_name] = $tool_perms;
671 }
672 }
673 }
674
675 return $this->toolPermissionTypes;
676 }
677 }
678