<?php
namespace App\EventSubscriber\Ticket;
use App\Entity\App\CustomField;
use App\Entity\App\Entity\Entity;
use App\Entity\App\GlobalConfiguration;
use App\Entity\App\Vendor;
use App\Repository\App\CustomFieldsRepository;
use App\Services\TicketService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\Translation\TranslatorInterface;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Repository\App\Ticket\TicketStateRepository;
use App\Repository\App\Ticket\TicketTypeRepository;
use App\Repository\App\RoleRepository;
use App\Exception\AccessDeniedException;
use App\Exception\NotFoundException;
use App\Services\VendorService;
use App\Services\UtilsService;
use App\Entity\App\Ticket\Ticket;
use App\Entity\App\Ticket\TicketState;
use App\Entity\App\User;
use App\Entity\App\Role;
use App\Entity\Chat\Chat;
class TicketPreWriteSubscriber implements EventSubscriberInterface
{
private $translator;
private $tokenStorage;
private $authorizationChecker;
private $vendorService;
private $ticketStateRepository;
private $ticketTypeRepository;
private $ticketTypeRequest;
private $ticketTypeIncidence;
private $ticketTypeWorkOrder;
private $roleRepository;
private $utilsService;
private $entityManager;
private $ticketService;
private $customFieldRepository;
public function __construct(
TranslatorInterface $translator,
TokenStorageInterface $tokenStorage,
AuthorizationCheckerInterface $checker,
VendorService $vendorService,
TicketStateRepository $ticketStateRepository,
TicketTypeRepository $ticketTypeRepository,
RoleRepository $roleRepository,
UtilsService $utilsService,
TicketService $ticketService,
EntityManagerInterface $entityManager,
CustomFieldsRepository $customFieldsRepository
) {
$this->translator = $translator;
$this->tokenStorage = $tokenStorage;
$this->authorizationChecker = $checker;
$this->vendorService = $vendorService;
$this->ticketStateRepository = $ticketStateRepository;
$this->ticketTypeRepository = $ticketTypeRepository;
$this->roleRepository = $roleRepository;
$this->utilsService = $utilsService;
$this->entityManager = $entityManager;
$this->ticketService = $ticketService;
$this->customFieldRepository = $customFieldsRepository;
}
/**
* @param ViewEvent $event
* @throws AccessDeniedException
* @throws NotFoundException
* @throws \Exception
*/
public function onKernelView(ViewEvent $event)
{
if ($this->utilsService->isAPublicRequest($event)) {
return;
}
$ticket = $event->getControllerResult();
$request = $event->getRequest();
$method = $request->getMethod();
$userCurrent = $this->tokenStorage->getToken()->getUser();
$vendorStaff = $userCurrent ? $userCurrent->getVendorStaff()[0] : null;
$vendor = is_null($vendorStaff) ? null : $vendorStaff->getVendor();
if (!($ticket instanceof Ticket) || !($userCurrent instanceof User) || !($vendor instanceof Vendor) ||
(Request::METHOD_POST !== $method && Request::METHOD_PUT !== $method && Request::METHOD_DELETE !== $method)
)
return;
if(!($userCurrent instanceof User))
throw new NotFoundException($this->translator->trans('User current not found'));
$authorization = false;
$controlAccess = [Role::ROLE_ADMIN, Role::ROLE_TASKMASTER];
$this->ticketTypeRequest = $this->ticketTypeRepository->findOneBy(['name' => 'request']);
$this->ticketTypeIncidence = $this->ticketTypeRepository->findOneBy(['name' => 'incidence']);
$this->ticketTypeWorkOrder = $this->ticketTypeRepository->findOneBy(['name' => 'work_order']);
$ticketTypeScheduledTask = $this->ticketTypeRepository->findOneBy(['name' => 'scheduled_task']);
$content = $request->getContent();
$params = json_decode($content, true);
if(Request::METHOD_POST === $method) {
if ($this->authorizationChecker->isGranted('ROLE_SUPERADMIN'))
{
$ticket = $this->addFieldsInCreate($ticket);
$event->setControllerResult($ticket);
return;
}
if ($ticket->getType() === $this->ticketTypeRequest or
$ticket->getType() === $this->ticketTypeIncidence
){
$controlAccess = [Role::ROLE_ALL];
$vendorStaff = $this->vendorService->getVendorStaff(null, $userCurrent, $ticket->getVendor());
if ($vendorStaff === null) {
throw new AccessDeniedException(
$this->translator->trans('Access denied. it does not belong to the vendor'),
['%vendor%' => $ticket->getVendor()->getName()]
);
}
}
if ($this->vendorService->isUserRoleInToVendor($ticket->getVendor(), $userCurrent, $controlAccess)) {
$authorization = true;
}
if ($authorization) {
$ticket = $this->addFieldsInCreate($ticket);
$ticket = $this->setTimezoneDate($ticket);
if ($ticket->getType() === $ticketTypeScheduledTask) {
$this->ticketService->setNextReminderDate($ticket);
$ticket = $this->setFormatRepeat($ticket, Request::METHOD_POST);
}
//$ticket = $this->setNullObjectEmpty($ticket, $params);
$event->setControllerResult($ticket);
}
}
if(Request::METHOD_PUT === $method) {
if ($this->authorizationChecker->isGranted('ROLE_SUPERADMIN'))
return;
if ($this->vendorService->isUserRoleInToVendor($ticket->getVendor(), $userCurrent, $controlAccess))
$authorization = true;
if (!$authorization && $ticket->getCreatedBy() === $userCurrent) {
$authorization = true;
if ($ticket->getType() === $this->ticketTypeRequest or
$ticket->getType() === $this->ticketTypeIncidence
) {
$this->actionDeniedByState($ticket, TicketState::STATE_ON_HOLD);
}
}
if ($authorization) {
$ticket = $this->setTimezoneDate($ticket);
//Depuramos los custom fields values según el template
$customFields = $this->customFieldRepository->findByVendorAndEntity($vendor, Entity::Ticket);
$customFieldIds = [];
foreach ($customFields as $customField){
foreach ($customField["properties"] as $properties){
$customFieldIds[]=$properties["createdAt"];
}
}
$customFieldValues =[];
foreach ($params["customFieldValues"] as $customFieldValue){
if(in_array($customFieldValue["propertyId"], $customFieldIds)){
$customFieldValues[] = (object)$customFieldValue;
}
}
$ticket->setCustomFieldValues($customFieldValues);
if ($ticket->getType() === $ticketTypeScheduledTask) {
//ACtualizamos el NextReminderDate
$this->ticketService->setNextReminderDate($ticket);
$ticket = $this->setFormatRepeat($ticket, Request::METHOD_PUT);
}
//$ticket = $this->setNullObjectEmpty($ticket, $params);
$event->setControllerResult($ticket);
}
}
if(Request::METHOD_DELETE === $method) {
if ($this->authorizationChecker->isGranted('ROLE_SUPERADMIN'))
return;
if ($this->vendorService->isUserRoleInToVendor($ticket->getVendor(), $userCurrent, $controlAccess))
$authorization = true;
if (!$authorization && $ticket->getCreatedBy() === $userCurrent) {
$authorization = true;
if ($ticket->getType() === $this->ticketTypeRequest or
$ticket->getType() === $this->ticketTypeIncidence
) {
$this->actionDeniedByState($ticket, TicketState::STATE_ON_HOLD);
}
if ($ticket->getType() === $this->ticketTypeWorkOrder) {
$this->actionDeniedByState($ticket, TicketState::STATE_IN_PROCESS);
}
}
}
if (!$authorization) {
$controlAccessTranslator = [];
foreach ($controlAccess as $roleName) {
$controlAccessTranslator[] = $this->translator->trans($roleName);
}
throw new AccessDeniedException(
$this->translator->trans('access_allowed_only_for') . (implode(', ', $controlAccessTranslator))
);
}
return;
}
/**
* @param Ticket $ticket
* @param $state
* @throws AccessDeniedException
*/
protected function actionDeniedByState(Ticket $ticket, $state)
{
$state = $this->ticketStateRepository->findOneBy(['name' => $state]);
if ($ticket->getState() !== $state) {
$message = $this->translator->trans(
'ticket.action.denied.by_state',
[
'%type%' => $this->translator->trans('ticket.type.'.$ticket->getType()->getName()),
'%state%' => $this->translator->trans('ticket.state.'.$ticket->getState()->getName())
]
);
throw new AccessDeniedException($message);
}
}
/**
* @param Ticket $ticket
* @return Ticket
* @throws AccessDeniedException
*/
protected function addFieldsInCreate(Ticket &$ticket)
{
$state = null;
$stateName = null;
if ($ticket->getType()->getStage() == Ticket::STAGE_REQUEST) {
$stateName = TicketState::STATE_ON_HOLD;
$state = $this->ticketStateRepository->findOneBy(['name' => TicketState::STATE_ON_HOLD]);
}
if ($ticket->getType()->getStage() == Ticket::STAGE_WORK_ORDER) {
$stateName = TicketState::STATE_IN_PROCESS;
$state = $this->ticketStateRepository->findOneBy(['name' => TicketState::STATE_IN_PROCESS]);
}
if (!$state instanceof TicketState) {
throw new AccessDeniedException($this->translator->trans('entity not found', [
'%entity%' => $this->translator->trans('state'),
'%entityId%' => $stateName
]));
}
$ticket->setState($state);
$chat = new Chat();
$chat->setType(Chat::TYPE_TICKET);
$this->entityManager->persist($chat);
$ticket->setChat($chat);
/*
$userCurrent = $this->tokenStorage->getToken()->getUser();
if ($ticket->getType() === $this->ticketTypeRequest or
$ticket->getType() === $this->ticketTypeIncidence
) {
if ($userCurrent instanceof User) {
if ($this->vendorService->isUserRoleInToVendor(
$ticket->getVendor(),
$userCurrent,
[Role::ROLE_USER]
)) {
$incidence = $this->ticketTypeRepository->findOneBy(['name' => 'incidence']);
if ($incidence instanceof TicketType) {
$ticket->setType($incidence);
}
}
TODO: CUSTOMER
if ($this->vendorService->isUserRoleInToVendor(
$ticket->getVendor(),
$userCurrent,
[Role::ROLE_CUSTOMER]
)) {
$vendorStaff = $this->vendorService->findOrCreateVendorStaff($ticket->getVendor(), $userCurrent, false);
if ($vendorStaff->getCompany()) {
$ticket->setCompany($vendorStaff->getCompany());
}
} else {
throw new NotFoundException($this->translator->trans('entity_not_found', ['entity' => 'user']));
}
}
*/
return $ticket;
}
/**
* @param Ticket $ticket
* @param string $method
* @return Ticket
* @throws \Exception
*/
protected function setFormatRepeat(Ticket &$ticket, string $method)
{
if($ticket->getRepeat()) {
if($ticket->getFrequency() === 'daily'){
$ticket->setFrequencyWeek(null);
$ticket->setFrequencyDayMonth(null);
}else
if ($ticket->getFrequency() === 'week') {
$ticket->setFrequencyDayMonth(null);
}else
if ($ticket->getFrequency() === 'month') {
$dayOfMonth = null;
if ($ticket->getReminderDate()) {
$dayOfMonth = $ticket->getReminderDate()->format('j');
if (in_array($dayOfMonth, [29, 30, 31])) {
$dayOfMonth = 0;
}
}
$ticket->setFrequencyDayMonth($dayOfMonth);
$ticket->setFrequencyWeek(null);
}else
if ($ticket->getFrequency() === 'year') {
$ticket->setFrequencyWeek(null);
$ticket->setFrequencyDayMonth(null);
}
} else {
$ticket->setFrequencyWeek(null);
$ticket->setFrequencyDayMonth(null);
$ticket->setFrequencyOffset(1);
$ticket->setFrequency("daily");
}
return $ticket;
}
/**
* @param Ticket $ticket
* @return Ticket
* @throws \Exception
*/
protected function setTimezoneDate(Ticket &$ticket)
{
if ($ticket->getDateExpiration() && !is_null($ticket->getDateExpiration())) {
$date = new \DateTime();
$date->setTimestamp($ticket->getDateExpiration()->getTimestamp());
$date->setTimezone(new \DateTimeZone('UTC'));
$ticket->setDateExpiration($date);
}
if ($ticket->getReminderDate() && !is_null($ticket->getReminderDate())) {
$date = new \DateTime();
$date->setTimestamp($ticket->getReminderDate()->getTimestamp());
$date->setTimezone(new \DateTimeZone('UTC'));
$ticket->setReminderDate($date);
//throw new \Exception('fecha elegida en UTC '.$ticket->getReminderDate()->format('Y-m-d H:i:s') .' Fecha del servidor en UTC '. date('Y-m-d H:i:s'));
}
if ($ticket->getReminderHour() && !is_null($ticket->getReminderHour())) {
$time = new \DateTime();
$time->setTimestamp($ticket->getReminderHour()->getTimestamp());
$time->setTimezone(new \DateTimeZone('UTC'));
$ticket->setReminderHour($time);
}
if ($ticket->getRepeatDateEnd() && !is_null($ticket->getRepeatDateEnd())) {
$date = new \DateTime();
$date->setTimestamp($ticket->getRepeatDateEnd()->getTimestamp());
$date->setTimezone(new \DateTimeZone('UTC'));
$ticket->setRepeatDateEnd($date);
}
return $ticket;
}
/**
* @param Ticket $ticket
* @param array $params
* @return Ticket
*/
protected function setNullObjectEmpty(Ticket &$ticket, array $params)
{
if (empty($params['incidenceType'])) {
$ticket->setIncidenceType(null);
}
if (empty($params['location'])) {
$ticket->setLocation(null);
}
if (empty($params['category'])) {
$ticket->setCategory(null);
}
return $ticket;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['onKernelView', EventPriorities::PRE_WRITE]
];
}
}