You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Mods-for-HESK-Netsyms/api/BusinessLogic/Tickets/TicketEditor.php

208 lines
8.5 KiB
PHP

<?php
namespace BusinessLogic\Tickets;
use BusinessLogic\DateTimeHelpers;
use BusinessLogic\Exceptions\AccessViolationException;
use BusinessLogic\Exceptions\ApiFriendlyException;
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Security\UserPrivilege;
use BusinessLogic\Security\UserToTicketChecker;
use BusinessLogic\Tickets\CustomFields\CustomFieldValidator;
use BusinessLogic\ValidationModel;
use BusinessLogic\Validators;
use Core\Constants\CustomField;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Tickets\TicketGateway;
class TicketEditor extends \BaseClass {
/* @var $ticketGateway TicketGateway */
private $ticketGateway;
/* @var $userToTicketChecker UserToTicketChecker */
private $userToTicketChecker;
/* @var $auditTrailGateway AuditTrailGateway */
private $auditTrailGateway;
function __construct(TicketGateway $ticketGateway,
UserToTicketChecker $userToTicketChecker,
AuditTrailGateway $auditTrailGateway) {
$this->ticketGateway = $ticketGateway;
$this->userToTicketChecker = $userToTicketChecker;
$this->auditTrailGateway = $auditTrailGateway;
}
/**
* @param $editTicketModel EditTicketModel
* @param $userContext UserContext
* @param $heskSettings array
* @throws ApiFriendlyException When the ticket isn't found for the ID
* @throws \Exception When the user doesn't have access to the ticket
*/
// TODO Unit Tests
function editTicket($editTicketModel, $userContext, $heskSettings) {
$ticket = $this->ticketGateway->getTicketById($editTicketModel->id, $heskSettings);
if ($ticket === null) {
throw new ApiFriendlyException("Ticket with ID {$editTicketModel->id} not found!", "Ticket not found", 404);
}
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, array(UserPrivilege::CAN_EDIT_TICKETS))) {
throw new AccessViolationException("User does not have access to ticket {$editTicketModel->id}");
}
$this->validate($editTicketModel, $ticket->categoryId, $heskSettings);
$ticket->name = $editTicketModel->name;
$ticket->email = $editTicketModel->email;
$ticket->subject = $editTicketModel->subject;
$ticket->message = $editTicketModel->message;
$ticket->customFields = $editTicketModel->customFields;
$this->ticketGateway->updateBasicTicketInfo($ticket, $heskSettings);
}
/**
* @param $editTicketModel EditTicketModel
* @param $categoryId int
* @param $heskSettings array
* @throws ValidationException When validation fails
*/
private function validate($editTicketModel, $categoryId, $heskSettings) {
$validationModel = new ValidationModel();
if ($editTicketModel->name === null || trim($editTicketModel->name) === '') {
$validationModel->errorKeys[] = 'NO_NAME';
}
if (!Validators::validateEmail($editTicketModel->email, $heskSettings['multi_eml'], false)) {
$validationModel->errorKeys[] = 'INVALID_OR_MISSING_EMAIL';
}
if ($heskSettings['require_subject'] === 1 &&
($editTicketModel->subject === NULL || $editTicketModel->subject === '')) {
$validationModel->errorKeys[] = 'SUBJECT_REQUIRED';
}
if ($heskSettings['require_message'] === 1 &&
($editTicketModel->message === NULL || $editTicketModel->message === '')) {
$validationModel->errorKeys[] = 'MESSAGE_REQUIRED';
}
foreach ($heskSettings['custom_fields'] as $key => $value) {
$customFieldNumber = intval(str_replace('custom', '', $key));
//TODO test this
if ($editTicketModel->customFields === null || !array_key_exists($customFieldNumber, $editTicketModel->customFields)) {
continue;
}
if ($value['use'] == 1 && CustomFieldValidator::isCustomFieldInCategory($customFieldNumber, intval($categoryId), false, $heskSettings)) {
$custom_field_value = $editTicketModel->customFields[$customFieldNumber];
if (empty($custom_field_value)) {
$validationModel->errorKeys[] = "CUSTOM_FIELD_{$customFieldNumber}_INVALID::NO_VALUE";
continue;
}
switch($value['type']) {
case CustomField::DATE:
if (!preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $custom_field_value)) {
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::INVALID_DATE';
} else {
// Actually validate based on range
$date = strtotime($custom_field_value . ' t00:00:00');
$dmin = strlen($value['value']['dmin']) ? strtotime($value['value']['dmin'] . ' t00:00:00') : false;
$dmax = strlen($value['value']['dmax']) ? strtotime($value['value']['dmax'] . ' t00:00:00') : false;
if ($dmin && $dmin > $date) {
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::DATE_BEFORE_MIN::MIN:' . date('Y-m-d', $dmin) . '::ENTERED:' . date('Y-m-d', $date);
} elseif ($dmax && $dmax < $date) {
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::DATE_AFTER_MAX::MAX:' . date('Y-m-d', $dmax) . '::ENTERED:' . date('Y-m-d', $date);
}
}
break;
case CustomField::EMAIL:
if (!Validators::validateEmail($custom_field_value, $value['value']['multiple'], false)) {
$validationModel->errorKeys[] = "CUSTOM_FIELD_{$customFieldNumber}_INVALID::INVALID_EMAIL";
}
break;
}
}
}
if ($editTicketModel->language === null ||
$editTicketModel->language === '') {
$validationModel->errorKeys[] = 'MISSING_LANGUAGE';
}
if (count($validationModel->errorKeys) > 0) {
throw new ValidationException($validationModel);
}
}
/**
* @param $id int
* @param $dueDate string
* @param $userContext UserContext
* @param $heskSettings array
* @return Ticket The updated ticket
*/
function updateDueDate($id, $dueDate, $userContext, $heskSettings) {
$ticket = $this->ticketGateway->getTicketById($id, $heskSettings);
$this->validateDueDate($ticket, $dueDate, $userContext, $heskSettings);
$this->ticketGateway->updateTicketDueDate($ticket->id, $dueDate, $heskSettings);
$event = AuditTrailEvent::DUE_DATE_REMOVED;
$replacementValues = array(0 => $userContext->name . ' (' . $userContext->username . ')');
if ($dueDate !== null) {
$event = AuditTrailEvent::DUE_DATE_CHANGED;
$replacementValues = array(
0 => $userContext->name . ' (' . $userContext->username . ')',
1 => date('Y-m-d H:i:s', strtotime($dueDate))
);
}
$this->auditTrailGateway->insertAuditTrailRecord($ticket->id,
AuditTrailEntityType::TICKET,
$event,
DateTimeHelpers::heskDate($heskSettings),
$replacementValues,
$heskSettings);
$ticket->dueDate = $dueDate;
return $ticket;
}
/**
* @param $ticket Ticket
* @param $dueDate string
* @param $userContext UserContext
* @param $heskSettings array
* @throws ValidationException When validation fails
*/
private function validateDueDate($ticket, $dueDate, $userContext, $heskSettings) {
$validationModel = new ValidationModel();
if ($ticket === null) {
$validationModel->errorKeys[] = 'TICKET_MUST_EXIST_FOR_ID';
}
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, array(UserPrivilege::CAN_CHANGE_DUE_DATE))) {
$validationModel->errorKeys[] = 'TICKET_MUST_BE_ACCESSIBLE_TO_USER';
}
if ($dueDate === false) {
$validationModel->errorKeys[] = 'DUE_DATE_MUST_BE_IN_VALID_FORMAT';
}
if (count($validationModel->errorKeys) > 0) {
throw new ValidationException($validationModel);
}
}
}