PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
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 1.7.4 All 35 releases
vikbooking / admin / controllers / taskmanager.php

taskmanager.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/controllers/taskmanager.php

648 lines 20.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 core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2025 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * VikBooking task manager controller (admin).
16 *
17 * @since 1.18.0 (J) - 1.8.0 (WP)
18 */
19 class VikBookingControllerTaskmanager extends JControllerAdmin
20 {
21 /**
22 * AJAX endpoint to render a task manager layout file.
23 *
24 * @return void
25 */
26 public function renderLayout()
27 {
28 $app = JFactory::getApplication();
29
30 if (!JSession::checkToken()) {
31 // missing CSRF-proof token
32 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
33 }
34
35 $type = $app->input->getString('type', '');
36 $data = (array) $app->input->get('data', [], 'array');
37
38 if (empty($type)) {
39 // invalid layout requested
40 VBOHttpDocument::getInstance($app)->close(404, sprintf('Could not find the layout [%s] to render.', $type));
41 }
42
43 // fetch the requested TM layout
44 $layout_data = [
45 'data' => $data,
46 ];
47
48 try {
49 $layout_html = JLayoutHelper::render('taskmanager.' . $type, $layout_data);
50 } catch (Exception $e) {
51 // raise the error caught
52 VBOHttpDocument::getInstance($app)->close($e->getCode() ?: 500, $e->getMessage());
53 }
54
55 // send the response to output
56 VBOHttpDocument::getInstance($app)->json([
57 'html' => $layout_html,
58 ]);
59 }
60
61 /**
62 * AJAX endpoint to create a new TM area.
63 *
64 * @return void
65 */
66 public function createArea()
67 {
68 $app = JFactory::getApplication();
69
70 if (!JSession::checkToken()) {
71 // missing CSRF-proof token
72 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
73 }
74
75 $area = (array) $app->input->get('area', [], 'array');
76 $area_settings = (array) $app->input->get('area_settings', [], 'array');
77
78 if (empty($area['instanceof'])) {
79 // missing task driver type for area
80 VBOHttpDocument::getInstance($app)->close(400, 'Missing task driver type for the area.');
81 }
82
83 // access the task manager object
84 $taskManager = VBOFactory::getTaskManager();
85
86 if (!$taskManager->driverExists($area['instanceof'])) {
87 // unknown task driver
88 VBOHttpDocument::getInstance($app)->close(400, sprintf('Unknown task driver [%s]', $area['instanceof']));
89 }
90
91 // normalize area fields
92 if (empty($area['name'])) {
93 // set the default task driver name
94 $area['name'] = $taskManager->getDriverInstance($area['instanceof'])->getName();
95 }
96
97 // set area task driver settings
98 $area['settings'] = $area_settings[$area['instanceof']] ?? [];
99
100 // filter out empty values
101 $area = array_filter($area);
102
103 // store the record
104 $areaId = VBOTaskModelArea::getInstance()->save($area);
105
106 if (!$areaId) {
107 // query failed
108 VBOHttpDocument::getInstance($app)->close(500, 'Could not store the database record. Please try again.');
109 }
110
111 // send the response to output
112 VBOHttpDocument::getInstance($app)->json([
113 'areaId' => $areaId,
114 ]);
115 }
116
117 /**
118 * AJAX endpoint to update an existing TM area.
119 *
120 * @return void
121 */
122 public function updateArea()
123 {
124 $app = JFactory::getApplication();
125
126 if (!JSession::checkToken()) {
127 // missing CSRF-proof token
128 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
129 }
130
131 $area = (array) $app->input->get('area', [], 'array');
132 $area_settings = (array) $app->input->get('area_settings', [], 'array');
133
134 if (empty($area['id'])) {
135 // missing area record id
136 VBOHttpDocument::getInstance($app)->close(400, 'Missing area record id.');
137 }
138
139 if (empty($area['instanceof'])) {
140 // missing task driver type for area
141 VBOHttpDocument::getInstance($app)->close(400, 'Missing task driver type for the area.');
142 }
143
144 // access the task manager object
145 $taskManager = VBOFactory::getTaskManager();
146
147 if (!$taskManager->driverExists($area['instanceof'])) {
148 // unknown task driver
149 VBOHttpDocument::getInstance($app)->close(400, sprintf('Unknown task driver [%s]', $area['instanceof']));
150 }
151
152 // normalize area fields
153 if (empty($area['name'])) {
154 // set the default task driver name
155 $area['name'] = $taskManager->getDriverInstance($area['instanceof'])->getName();
156 }
157
158 // set area task driver settings
159 $area['settings'] = $area_settings[$area['instanceof']] ?? [];
160
161 // filter out empty values
162 $area = array_filter($area);
163
164 // update the existing record
165 if (!VBOTaskModelArea::getInstance()->update($area)) {
166 // query failed
167 VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.');
168 }
169
170 // send the response to output
171 VBOHttpDocument::getInstance($app)->json([
172 'areaId' => $area['id'],
173 ]);
174 }
175
176 /**
177 * AJAX endpoint to delete an existing TM area.
178 *
179 * @return void
180 */
181 public function deleteArea()
182 {
183 $app = JFactory::getApplication();
184
185 if (!JSession::checkToken()) {
186 // missing CSRF-proof token
187 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
188 }
189
190 $area_id = $app->input->getInt('area_id', 0);
191
192 if (empty($area_id)) {
193 // missing area record id
194 VBOHttpDocument::getInstance($app)->close(400, 'Missing area record id.');
195 }
196
197 $record = VBOTaskModelArea::getInstance()->getItem($area_id);
198
199 if (!$record) {
200 // area record not found
201 VBOHttpDocument::getInstance($app)->close(404, 'Area record not found.');
202 }
203
204 if (!VBOTaskModelArea::getInstance()->delete($record->id)) {
205 // query error
206 VBOHttpDocument::getInstance($app)->close(500, 'Could not delete the area record.');
207 }
208
209 // send the response to output
210 VBOHttpDocument::getInstance($app)->json([
211 'success' => 1,
212 ]);
213 }
214
215 /**
216 * AJAX endpoint to toggle the display state for an existing TM area.
217 *
218 * @return void
219 */
220 public function toggleAreaDisplay()
221 {
222 $app = JFactory::getApplication();
223
224 if (!JSession::checkToken()) {
225 // missing CSRF-proof token
226 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
227 }
228
229 $area = (array) $app->input->get('area', [], 'array');
230
231 if (empty($area['id'])) {
232 // missing area record id
233 VBOHttpDocument::getInstance($app)->close(400, 'Missing area record id.');
234 }
235
236 // get area record
237 $record = VBOTaskModelArea::getInstance()->getItem($area['id']);
238 if (!$record) {
239 // area not found
240 VBOHttpDocument::getInstance($app)->close(404, 'Area record not found.');
241 }
242
243 // build record data payload
244 $data = [
245 'id' => $record->id,
246 // set or toggle display state
247 'display' => isset($area['display']) ? intval((bool) $area['display']) : intval(!((bool) $record->display)),
248 ];
249
250 // update the existing record
251 if (!VBOTaskModelArea::getInstance()->update($data)) {
252 // query failed
253 VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.');
254 }
255
256 // update visible areas in session
257 if ($data['display']) {
258 VBOFactory::getTaskManager()->setVisibleArea($record->id);
259 } else {
260 VBOFactory::getTaskManager()->unsetVisibleArea($record->id);
261 }
262
263 // send the response to output
264 VBOHttpDocument::getInstance($app)->json([
265 'areaId' => $record->id,
266 'status' => $data['display'],
267 ]);
268 }
269
270 /**
271 * AJAX endpoint to update an existing color tag.
272 *
273 * @return void
274 */
275 public function updateColorTag()
276 {
277 $app = JFactory::getApplication();
278
279 if (!JSession::checkToken()) {
280 // missing CSRF-proof token
281 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
282 }
283
284 $colortag = (array) $app->input->get('colortag', [], 'array');
285
286 if (empty($colortag['id'])) {
287 // missing color tag record id
288 VBOHttpDocument::getInstance($app)->close(400, 'Missing color tag record id.');
289 }
290
291 // get color tag record
292 $record = VBOTaskModelColortag::getInstance()->getItem($colortag['id']);
293 if (!$record) {
294 // color tag not found
295 VBOHttpDocument::getInstance($app)->close(404, 'Color tag record not found.');
296 }
297
298 // update the existing record
299 if (!VBOTaskModelColortag::getInstance()->update($colortag)) {
300 // query failed
301 VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.');
302 }
303
304 // send the response to output
305 VBOHttpDocument::getInstance($app)->json([
306 'success' => 1,
307 ]);
308 }
309
310 /**
311 * AJAX endpoint to delete an existing color tag.
312 *
313 * @return void
314 */
315 public function deleteColorTag()
316 {
317 $app = JFactory::getApplication();
318
319 if (!JSession::checkToken()) {
320 // missing CSRF-proof token
321 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
322 }
323
324 $colortag = (array) $app->input->get('colortag', [], 'array');
325
326 if (empty($colortag['id'])) {
327 // missing color tag record id
328 VBOHttpDocument::getInstance($app)->close(400, 'Missing color tag record id.');
329 }
330
331 // get color tag record
332 $record = VBOTaskModelColortag::getInstance()->getItem($colortag['id']);
333 if (!$record) {
334 // color tag not found
335 VBOHttpDocument::getInstance($app)->close(404, 'Color tag record not found.');
336 }
337
338 // delete the existing record
339 if (!VBOTaskModelColortag::getInstance()->delete($colortag['id'])) {
340 // query failed
341 VBOHttpDocument::getInstance($app)->close(500, 'Could not delete the database record. Please try again.');
342 }
343
344 // send the response to output
345 VBOHttpDocument::getInstance($app)->json([
346 'success' => 1,
347 ]);
348 }
349
350 /**
351 * AJAX endpoint to create a new TM task.
352 *
353 * @return void
354 */
355 public function createTask()
356 {
357 $app = JFactory::getApplication();
358
359 if (!JSession::checkToken()) {
360 // missing CSRF-proof token
361 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
362 }
363
364 $data = (array) $app->input->get('data', [], 'array');
365
366 if (empty($data['id_area'])) {
367 // missing area ID
368 VBOHttpDocument::getInstance($app)->close(400, 'Missing task project/area ID.');
369 }
370
371 if (empty($data['title'])) {
372 // missing task title
373 VBOHttpDocument::getInstance($app)->close(400, 'Please provide a title for the task.');
374 }
375
376 // store the record
377 $taskId = VBOTaskModelTask::getInstance()->save($data);
378
379 if (!$taskId) {
380 // query failed
381 VBOHttpDocument::getInstance($app)->close(500, 'Could not store the task database record. Please try again.');
382 }
383
384 // send the response to output
385 VBOHttpDocument::getInstance($app)->json([
386 'taskId' => $taskId,
387 ]);
388 }
389
390 /**
391 * AJAX endpoint to update an existing TM task.
392 *
393 * @return void
394 */
395 public function updateTask()
396 {
397 $app = JFactory::getApplication();
398
399 if (!JSession::checkToken()) {
400 // missing CSRF-proof token
401 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
402 }
403
404 $data = (array) $app->input->get('data', [], 'array');
405
406 if (empty($data['id'])) {
407 // missing task id
408 VBOHttpDocument::getInstance($app)->close(400, 'Missing task record ID.');
409 }
410
411 // update the existing record
412 if (!VBOTaskModelTask::getInstance()->update($data)) {
413 // query failed
414 VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.');
415 }
416
417 // send the response to output
418 VBOHttpDocument::getInstance($app)->json([
419 'success' => 1,
420 'taskId' => $data['id'],
421 ]);
422 }
423
424 /**
425 * AJAX endpoint to delete an existing TM task.
426 *
427 * @return void
428 */
429 public function deleteTask()
430 {
431 $app = JFactory::getApplication();
432
433 if (!JSession::checkToken()) {
434 // missing CSRF-proof token
435 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
436 }
437
438 $data = (array) $app->input->get('data', [], 'array');
439
440 if (empty($data['id'])) {
441 // missing task id
442 VBOHttpDocument::getInstance($app)->close(400, 'Missing task record ID.');
443 }
444
445 // get task record
446 $record = VBOTaskModelTask::getInstance()->getItem($data['id']);
447 if (!$record) {
448 // task not found
449 VBOHttpDocument::getInstance($app)->close(404, 'Task record not found.');
450 }
451
452 // delete the existing record
453 if (!VBOTaskModelTask::getInstance()->delete($data['id'])) {
454 // query failed
455 VBOHttpDocument::getInstance($app)->close(500, 'Could not delete the database record. Please try again.');
456 }
457
458 // send the response to output
459 VBOHttpDocument::getInstance($app)->json([
460 'success' => 1,
461 ]);
462 }
463
464 /**
465 * AJAX endpoint to repeat (re-schedule) an existing TM task.
466 *
467 * @return void
468 *
469 * @since 1.18.4 (J) - 1.8.4 (WP)
470 */
471 public function repeatTask()
472 {
473 $app = JFactory::getApplication();
474
475 if (!JSession::checkToken()) {
476 // missing CSRF-proof token
477 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
478 }
479
480 $task_id = $app->input->getUInt('task_id', 0);
481 $interval = $app->input->getString('interval', '');
482
483 if (!$interval) {
484 // missing value
485 VBOHttpDocument::getInstance($app)->close(400, 'Repeating value is required.');
486 }
487
488 // get task record
489 $record = VBOTaskModelTask::getInstance()->getItem($task_id);
490 if (!$record) {
491 // task not found
492 VBOHttpDocument::getInstance($app)->close(404, 'Task record not found.');
493 }
494
495 // wrap task record into a registry
496 $task = VBOTaskTaskregistry::getInstance((array) $record);
497
498 // task due date and time
499 $due_date = $task->getDueDate(true, 'Y-m-d H:i:s');
500 $due_time = $task->getDueDate(true, 'H:i:s');
501
502 // normalize properties for storing a new task record
503 unset(
504 $record->id,
505 $record->createdon,
506 $record->modifiedon,
507 $record->beganon,
508 $record->finishedon,
509 $record->beganby,
510 $record->finishedby,
511 $record->archived,
512 $record->workstartedon,
513 $record->realduration
514 );
515
516 // calculate the new due date
517 if (preg_match('/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/', $interval)) {
518 // we've got a date in Y-m-d format
519 $record->dueon = $interval . ' ' . $due_time;
520 } elseif (preg_match('/^([0-9]+)\s?(days?|weeks?|months?)$/i', $interval, $matches)) {
521 $record->dueon = date('Y-m-d H:i:s', strtotime(sprintf('+%d %s', (int) $matches[1], strtolower($matches[2])), strtotime($due_date)));
522 } else {
523 // unrecognized repeating interval
524 VBOHttpDocument::getInstance($app)->close(400, 'Unrecognized repeating interval.');
525 }
526
527 // keep the same assignees as before
528 $record->assignees = $task->getAssigneeIds();
529
530 // store the record
531 $newTaskId = VBOTaskModelTask::getInstance()->save($record);
532
533 if (!$newTaskId) {
534 // query failed
535 VBOHttpDocument::getInstance($app)->close(500, 'Could not store the task database record. Please try again.');
536 }
537
538 // send the response to output
539 VBOHttpDocument::getInstance($app)->json([
540 'taskId' => $newTaskId,
541 ]);
542 }
543
544 /**
545 * AJAX endpoint to load the tasks for a given area, listings and dates.
546 *
547 * @return void
548 */
549 public function loadAreaListingTasks()
550 {
551 $app = JFactory::getApplication();
552
553 if (!JSession::checkToken()) {
554 // missing CSRF-proof token
555 VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN'));
556 }
557
558 $area_id = $app->input->getUInt('area_id', 0);
559 $room_ids = (array) $app->input->get('room_ids', [], 'array');
560 $from_date = $app->input->getString('from_date', date('Y-m-01'));
561 $to_date = $app->input->getString('to_date', date('Y-m-t'));
562
563 if (!$area_id || !$room_ids) {
564 // missing mandatory values
565 VBOHttpDocument::getInstance($app)->close(400, 'Missing area/project ID or listing IDs.');
566 }
567
568 // access the task manager object
569 $taskManager = VBOFactory::getTaskManager();
570
571 // get the area record
572 $area = VBOTaskModelArea::getInstance()->getItem($area_id);
573
574 if (!$area) {
575 // area/project id not found
576 VBOHttpDocument::getInstance($app)->close(404, 'Invalid area/project ID.');
577 }
578
579 // wrap the area record into a registry
580 $areaRegistry = VBOTaskArea::getInstance((array) $area);
581
582 // normalize area record object
583 if (empty($area->icon) && !empty($area->instanceof)) {
584 $area->icon = $areaRegistry->getIcon();
585 }
586 if (!empty($area->icon)) {
587 $area->icon_class = VikBookingIcons::i($area->icon);
588 }
589
590 // pool of listing tasks
591 $listingTasks = [];
592
593 // build filters
594 $filters = [
595 'id_area' => $area_id,
596 'id_rooms' => $room_ids,
597 'dates' => $from_date . ':' . $to_date,
598 ];
599
600 // load tasks according to filters, by always forcing/injecting the area IDs and the dates
601 foreach (VBOTaskModelTask::getInstance()->filterItems($filters, 0, 0) as $taskRecord) {
602 // wrap task record into a registry
603 $task = VBOTaskTaskregistry::getInstance((array) $taskRecord);
604
605 // task listing id
606 $listing_id = $task->getListingId();
607
608 // task due date key
609 $date_key = $task->getDueDate(true, 'Y-m-d');
610
611 if (!isset($listingTasks[$listing_id])) {
612 // start container
613 $listingTasks[$listing_id] = [];
614 }
615
616 if (!isset($listingTasks[$listing_id][$date_key])) {
617 // start container
618 $listingTasks[$listing_id][$date_key] = [];
619 }
620
621 // build task status color enum
622 $statusColorEnum = '';
623 if ($taskManager->statusTypeExists($task->getStatus())) {
624 $statusColorEnum = $taskManager->getStatusTypeInstance($task->getStatus())->getColor();
625 }
626
627 // push listing day task information
628 $listingTasks[$listing_id][$date_key][] = [
629 'id' => $task->getID(),
630 'area_id' => $task->getAreaID(),
631 'bid' => $task->getBookingId(),
632 'title' => $task->getTitle(),
633 'status' => $task->getStatus(),
634 'color' => $statusColorEnum,
635 'dueon' => $task->getDueDate(true, 'Y-m-d H:i'),
636 'scheduling' => $task->getScheduling(),
637 ];
638 }
639
640 // send response to output
641 VBOHttpDocument::getInstance($app)->json([
642 'area' => $area,
643 'listings' => $listingTasks,
644 'listingIds' => $areaRegistry->getListingIds(),
645 ]);
646 }
647 }
648