PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
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.16, at site/helpers/operator.php

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