close(403, JText::translate('JINVALID_TOKEN')); } $type = $app->input->getString('type', ''); $data = (array) $app->input->get('data', [], 'array'); if (empty($type)) { // invalid layout requested VBOHttpDocument::getInstance($app)->close(404, sprintf('Could not find the layout [%s] to render.', $type)); } // fetch the requested TM layout $layout_data = [ 'data' => $data, ]; try { $layout_html = JLayoutHelper::render('taskmanager.' . $type, $layout_data); } catch (Exception $e) { // raise the error caught VBOHttpDocument::getInstance($app)->close($e->getCode() ?: 500, $e->getMessage()); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'html' => $layout_html, ]); } /** * AJAX endpoint to create a new TM area. * * @return void */ public function createArea() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $area = (array) $app->input->get('area', [], 'array'); $area_settings = (array) $app->input->get('area_settings', [], 'array'); if (empty($area['instanceof'])) { // missing task driver type for area VBOHttpDocument::getInstance($app)->close(400, 'Missing task driver type for the area.'); } // access the task manager object $taskManager = VBOFactory::getTaskManager(); if (!$taskManager->driverExists($area['instanceof'])) { // unknown task driver VBOHttpDocument::getInstance($app)->close(400, sprintf('Unknown task driver [%s]', $area['instanceof'])); } // normalize area fields if (empty($area['name'])) { // set the default task driver name $area['name'] = $taskManager->getDriverInstance($area['instanceof'])->getName(); } // set area task driver settings $area['settings'] = $area_settings[$area['instanceof']] ?? []; // filter out empty values $area = array_filter($area); // store the record $areaId = VBOTaskModelArea::getInstance()->save($area); if (!$areaId) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not store the database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'areaId' => $areaId, ]); } /** * AJAX endpoint to update an existing TM area. * * @return void */ public function updateArea() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $area = (array) $app->input->get('area', [], 'array'); $area_settings = (array) $app->input->get('area_settings', [], 'array'); if (empty($area['id'])) { // missing area record id VBOHttpDocument::getInstance($app)->close(400, 'Missing area record id.'); } if (empty($area['instanceof'])) { // missing task driver type for area VBOHttpDocument::getInstance($app)->close(400, 'Missing task driver type for the area.'); } // access the task manager object $taskManager = VBOFactory::getTaskManager(); if (!$taskManager->driverExists($area['instanceof'])) { // unknown task driver VBOHttpDocument::getInstance($app)->close(400, sprintf('Unknown task driver [%s]', $area['instanceof'])); } // normalize area fields if (empty($area['name'])) { // set the default task driver name $area['name'] = $taskManager->getDriverInstance($area['instanceof'])->getName(); } // set area task driver settings $area['settings'] = $area_settings[$area['instanceof']] ?? []; // filter out empty values $area = array_filter($area); // update the existing record if (!VBOTaskModelArea::getInstance()->update($area)) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'areaId' => $area['id'], ]); } /** * AJAX endpoint to delete an existing TM area. * * @return void */ public function deleteArea() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $area_id = $app->input->getInt('area_id', 0); if (empty($area_id)) { // missing area record id VBOHttpDocument::getInstance($app)->close(400, 'Missing area record id.'); } $record = VBOTaskModelArea::getInstance()->getItem($area_id); if (!$record) { // area record not found VBOHttpDocument::getInstance($app)->close(404, 'Area record not found.'); } if (!VBOTaskModelArea::getInstance()->delete($record->id)) { // query error VBOHttpDocument::getInstance($app)->close(500, 'Could not delete the area record.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'success' => 1, ]); } /** * AJAX endpoint to toggle the display state for an existing TM area. * * @return void */ public function toggleAreaDisplay() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $area = (array) $app->input->get('area', [], 'array'); if (empty($area['id'])) { // missing area record id VBOHttpDocument::getInstance($app)->close(400, 'Missing area record id.'); } // get area record $record = VBOTaskModelArea::getInstance()->getItem($area['id']); if (!$record) { // area not found VBOHttpDocument::getInstance($app)->close(404, 'Area record not found.'); } // build record data payload $data = [ 'id' => $record->id, // set or toggle display state 'display' => isset($area['display']) ? intval((bool) $area['display']) : intval(!((bool) $record->display)), ]; // update the existing record if (!VBOTaskModelArea::getInstance()->update($data)) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.'); } // update visible areas in session if ($data['display']) { VBOFactory::getTaskManager()->setVisibleArea($record->id); } else { VBOFactory::getTaskManager()->unsetVisibleArea($record->id); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'areaId' => $record->id, 'status' => $data['display'], ]); } /** * AJAX endpoint to update an existing color tag. * * @return void */ public function updateColorTag() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $colortag = (array) $app->input->get('colortag', [], 'array'); if (empty($colortag['id'])) { // missing color tag record id VBOHttpDocument::getInstance($app)->close(400, 'Missing color tag record id.'); } // get color tag record $record = VBOTaskModelColortag::getInstance()->getItem($colortag['id']); if (!$record) { // color tag not found VBOHttpDocument::getInstance($app)->close(404, 'Color tag record not found.'); } // update the existing record if (!VBOTaskModelColortag::getInstance()->update($colortag)) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'success' => 1, ]); } /** * AJAX endpoint to delete an existing color tag. * * @return void */ public function deleteColorTag() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $colortag = (array) $app->input->get('colortag', [], 'array'); if (empty($colortag['id'])) { // missing color tag record id VBOHttpDocument::getInstance($app)->close(400, 'Missing color tag record id.'); } // get color tag record $record = VBOTaskModelColortag::getInstance()->getItem($colortag['id']); if (!$record) { // color tag not found VBOHttpDocument::getInstance($app)->close(404, 'Color tag record not found.'); } // delete the existing record if (!VBOTaskModelColortag::getInstance()->delete($colortag['id'])) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not delete the database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'success' => 1, ]); } /** * AJAX endpoint to create a new TM task. * * @return void */ public function createTask() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $data = (array) $app->input->get('data', [], 'array'); if (empty($data['id_area'])) { // missing area ID VBOHttpDocument::getInstance($app)->close(400, 'Missing task project/area ID.'); } if (empty($data['title'])) { // missing task title VBOHttpDocument::getInstance($app)->close(400, 'Please provide a title for the task.'); } // store the record $taskId = VBOTaskModelTask::getInstance()->save($data); if (!$taskId) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not store the task database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'taskId' => $taskId, ]); } /** * AJAX endpoint to update an existing TM task. * * @return void */ public function updateTask() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $data = (array) $app->input->get('data', [], 'array'); if (empty($data['id'])) { // missing task id VBOHttpDocument::getInstance($app)->close(400, 'Missing task record ID.'); } // update the existing record if (!VBOTaskModelTask::getInstance()->update($data)) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not update the database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'success' => 1, 'taskId' => $data['id'], ]); } /** * AJAX endpoint to delete an existing TM task. * * @return void */ public function deleteTask() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $data = (array) $app->input->get('data', [], 'array'); if (empty($data['id'])) { // missing task id VBOHttpDocument::getInstance($app)->close(400, 'Missing task record ID.'); } // get task record $record = VBOTaskModelTask::getInstance()->getItem($data['id']); if (!$record) { // task not found VBOHttpDocument::getInstance($app)->close(404, 'Task record not found.'); } // delete the existing record if (!VBOTaskModelTask::getInstance()->delete($data['id'])) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not delete the database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'success' => 1, ]); } /** * AJAX endpoint to repeat (re-schedule) an existing TM task. * * @return void * * @since 1.18.4 (J) - 1.8.4 (WP) */ public function repeatTask() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $task_id = $app->input->getUInt('task_id', 0); $interval = $app->input->getString('interval', ''); if (!$interval) { // missing value VBOHttpDocument::getInstance($app)->close(400, 'Repeating value is required.'); } // get task record $record = VBOTaskModelTask::getInstance()->getItem($task_id); if (!$record) { // task not found VBOHttpDocument::getInstance($app)->close(404, 'Task record not found.'); } // wrap task record into a registry $task = VBOTaskTaskregistry::getInstance((array) $record); // task due date and time $due_date = $task->getDueDate(true, 'Y-m-d H:i:s'); $due_time = $task->getDueDate(true, 'H:i:s'); // normalize properties for storing a new task record unset( $record->id, $record->createdon, $record->modifiedon, $record->beganon, $record->finishedon, $record->beganby, $record->finishedby, $record->archived, $record->workstartedon, $record->realduration ); // calculate the new due date if (preg_match('/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$/', $interval)) { // we've got a date in Y-m-d format $record->dueon = $interval . ' ' . $due_time; } elseif (preg_match('/^([0-9]+)\s?(days?|weeks?|months?)$/i', $interval, $matches)) { $record->dueon = date('Y-m-d H:i:s', strtotime(sprintf('+%d %s', (int) $matches[1], strtolower($matches[2])), strtotime($due_date))); } else { // unrecognized repeating interval VBOHttpDocument::getInstance($app)->close(400, 'Unrecognized repeating interval.'); } // keep the same assignees as before $record->assignees = $task->getAssigneeIds(); // store the record $newTaskId = VBOTaskModelTask::getInstance()->save($record); if (!$newTaskId) { // query failed VBOHttpDocument::getInstance($app)->close(500, 'Could not store the task database record. Please try again.'); } // send the response to output VBOHttpDocument::getInstance($app)->json([ 'taskId' => $newTaskId, ]); } /** * AJAX endpoint to load the tasks for a given area, listings and dates. * * @return void */ public function loadAreaListingTasks() { $app = JFactory::getApplication(); if (!JSession::checkToken()) { // missing CSRF-proof token VBOHttpDocument::getInstance($app)->close(403, JText::translate('JINVALID_TOKEN')); } $area_id = $app->input->getUInt('area_id', 0); $room_ids = (array) $app->input->get('room_ids', [], 'array'); $from_date = $app->input->getString('from_date', date('Y-m-01')); $to_date = $app->input->getString('to_date', date('Y-m-t')); if (!$area_id || !$room_ids) { // missing mandatory values VBOHttpDocument::getInstance($app)->close(400, 'Missing area/project ID or listing IDs.'); } // access the task manager object $taskManager = VBOFactory::getTaskManager(); // get the area record $area = VBOTaskModelArea::getInstance()->getItem($area_id); if (!$area) { // area/project id not found VBOHttpDocument::getInstance($app)->close(404, 'Invalid area/project ID.'); } // wrap the area record into a registry $areaRegistry = VBOTaskArea::getInstance((array) $area); // normalize area record object if (empty($area->icon) && !empty($area->instanceof)) { $area->icon = $areaRegistry->getIcon(); } if (!empty($area->icon)) { $area->icon_class = VikBookingIcons::i($area->icon); } // pool of listing tasks $listingTasks = []; // build filters $filters = [ 'id_area' => $area_id, 'id_rooms' => $room_ids, 'dates' => $from_date . ':' . $to_date, ]; // load tasks according to filters, by always forcing/injecting the area IDs and the dates foreach (VBOTaskModelTask::getInstance()->filterItems($filters, 0, 0) as $taskRecord) { // wrap task record into a registry $task = VBOTaskTaskregistry::getInstance((array) $taskRecord); // task listing id $listing_id = $task->getListingId(); // task due date key $date_key = $task->getDueDate(true, 'Y-m-d'); if (!isset($listingTasks[$listing_id])) { // start container $listingTasks[$listing_id] = []; } if (!isset($listingTasks[$listing_id][$date_key])) { // start container $listingTasks[$listing_id][$date_key] = []; } // build task status color enum $statusColorEnum = ''; if ($taskManager->statusTypeExists($task->getStatus())) { $statusColorEnum = $taskManager->getStatusTypeInstance($task->getStatus())->getColor(); } // push listing day task information $listingTasks[$listing_id][$date_key][] = [ 'id' => $task->getID(), 'area_id' => $task->getAreaID(), 'bid' => $task->getBookingId(), 'title' => $task->getTitle(), 'status' => $task->getStatus(), 'color' => $statusColorEnum, 'dueon' => $task->getDueDate(true, 'Y-m-d H:i'), 'scheduling' => $task->getScheduling(), ]; } // send response to output VBOHttpDocument::getInstance($app)->json([ 'area' => $area, 'listings' => $listingTasks, 'listingIds' => $areaRegistry->getListingIds(), ]); } }