vendor/uvdesk/core-framework/Controller/Ticket.php line 68

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\CoreFrameworkBundle\Controller;
  3. use Symfony\Component\HttpFoundation\Request;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\EventDispatcher\GenericEvent;
  6. use Webkul\UVDesk\CoreFrameworkBundle\Form as CoreFrameworkBundleForms;
  7. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  8. use Webkul\UVDesk\CoreFrameworkBundle\Entity as CoreFrameworkBundleEntities;
  9. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  10. use Webkul\UVDesk\CoreFrameworkBundle\DataProxies as CoreFrameworkBundleDataProxies;
  11. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  12. use Webkul\UVDesk\CoreFrameworkBundle\Tickets\QuickActionButtonCollection;
  13. use Webkul\UVDesk\CoreFrameworkBundle\Services\CustomFieldsService;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Repository\TicketRepository;
  15. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  16. use Symfony\Contracts\Translation\TranslatorInterface;
  17. use Webkul\UVDesk\CoreFrameworkBundle\Services\UVDeskService;
  18. use Webkul\UVDesk\CoreFrameworkBundle\Services\TicketService;
  19. use Webkul\UVDesk\CoreFrameworkBundle\Services\EmailService;
  20. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  21. use Symfony\Component\HttpKernel\KernelInterface;
  22. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  23. use Symfony\Component\DependencyInjection\ContainerInterface;
  24. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Attachment;
  25. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Thread;
  26. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket as CoreBundleTicket;
  27. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Tag;
  28. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketType;
  29. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportRole;
  30. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  31. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketPriority;
  32. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketStatus;
  33. class Ticket extends AbstractController
  34. {
  35.     private $userService;
  36.     private $translator;
  37.     private $eventDispatcher;
  38.     private $ticketService;
  39.     private $emailService;
  40.     private $kernel;
  41.     private $customFieldsService;
  42.     public function __construct(UserService $userServiceTranslatorInterface $translatorTicketService $ticketServiceEmailService $emailServiceEventDispatcherInterface $eventDispatcherKernelInterface $kernelCustomFieldsService $customFieldsService)
  43.     {
  44.         $this->userService $userService;
  45.         $this->emailService $emailService;
  46.         $this->translator $translator;
  47.         $this->ticketService $ticketService;
  48.         $this->eventDispatcher $eventDispatcher;
  49.         $this->kernel $kernel;
  50.         $this->customFieldsService $customFieldsService;
  51.     }
  52.     public function listTicketCollection(Request $request)
  53.     {
  54.         $entityManager $this->getDoctrine()->getManager();
  55.         return $this->render('@UVDeskCoreFramework//ticketList.html.twig', [
  56.             'ticketStatusCollection' => $entityManager->getRepository(TicketStatus::class)->findAll(),
  57.             'ticketTypeCollection' => $entityManager->getRepository(TicketType::class)->findByIsActive(true),
  58.             'ticketPriorityCollection' => $entityManager->getRepository(TicketPriority::class)->findAll(),
  59.         ]);
  60.     }
  61.     public function loadTicket($ticketIdQuickActionButtonCollection $quickActionButtonCollectionContainerInterface $container)
  62.     {
  63.         $entityManager $this->getDoctrine()->getManager();
  64.         $userRepository $entityManager->getRepository(User::class);
  65.         $ticketRepository $entityManager->getRepository(CoreBundleTicket::class);
  66.         $ticket $ticketRepository->findOneById($ticketId);
  67.         
  68.         if (empty($ticket)) {
  69.             throw new NotFoundHttpException('Page not found!');
  70.         }
  71.         
  72.         $user $this->userService->getSessionUser();
  73.         
  74.         // Proceed only if user has access to the resource
  75.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  76.             throw new \Exception('Access Denied'403);
  77.         }
  78.         $agent $ticket->getAgent();
  79.         $customer $ticket->getCustomer();
  80.      
  81.     if($agent != null && !empty($agent)){    
  82.         $ticketAssignAgent $agent->getId();
  83.         $currentUser $user->getId();
  84.     }
  85.         
  86.         // Mark as viewed by agents
  87.         if (false == $ticket->getIsAgentViewed()) {
  88.             $ticket->setIsAgentViewed(true);
  89.             $entityManager->persist($ticket);
  90.             $entityManager->flush();
  91.         }
  92.     
  93.         // Ticket Authorization
  94.         $supportRole $user->getCurrentInstance()->getSupportRole()->getCode(); 
  95.         switch($supportRole) {
  96.             case 'ROLE_ADMIN':
  97.             case 'ROLE_SUPER_ADMIN':
  98.                 break;
  99.             case 'ROLE_AGENT':
  100.                 $accessLevel = (int) $user->getCurrentInstance()->getTicketAccessLevel();
  101.                 switch($accessLevel) {
  102.                     case TicketRepository::TICKET_GLOBAL_ACCESS:
  103.                         break;
  104.                     case TicketRepository::TICKET_GROUP_ACCESS:
  105.                         $supportGroups array_map(function($supportGroup) { return $supportGroup->getId(); }, $user->getCurrentInstance()->getSupportGroups()->getValues());                       
  106.                         $ticketAccessableGroups $ticket->getSupportGroup() ? [$ticket->getSupportGroup()->getId()] : [];
  107.  
  108.                         if ($ticket->getSupportTeam()) {
  109.                             $ticketSupportTeamGroups array_map(function($supportGroup) { return $supportGroup->getId(); }, $ticket->getSupportTeam()->getSupportGroups()->getValues());
  110.                             $ticketAccessableGroups array_merge($ticketAccessableGroups$ticketSupportTeamGroups);
  111.                         }
  112.                         $isAccessableGroupFound false;
  113.                         foreach($ticketAccessableGroups as $groupId) {
  114.                             if (in_array($groupId$supportGroups)) {
  115.                                 $isAccessableGroupFound true;
  116.                                 break;
  117.                             }
  118.                         }
  119.                         if (!$isAccessableGroupFound && !($ticketAssignAgent == $currentUser)) {
  120.                             throw new NotFoundHttpException('Page not found!');
  121.                         }
  122.                         break;
  123.                     case TicketRepository::TICKET_TEAM_ACCESS:
  124.                         $supportTeams array_map(function($supportTeam) { return $supportTeam->getId(); }, $user->getCurrentInstance()->getSupportTeams()->getValues());                         
  125.                         $supportTeam $ticket->getSupportTeam();
  126.                         if (!($supportTeam && in_array($supportTeam->getId(), $supportTeams)) && !($ticketAssignAgent == $currentUser)) {
  127.                             throw new NotFoundHttpException('Page not found!');
  128.                         }
  129.                         break;
  130.                     default:
  131.                         $collaborators array_map( function ($collaborator) { return $collaborator->getId(); }, $ticket->getCollaborators()->getValues());
  132.                         $accessableAgents array_merge($collaborators$ticket->getAgent() ? [$ticket->getAgent()->getId()] : []);
  133.                         if (!in_array($user->getId(), $accessableAgents)) {
  134.                             throw new NotFoundHttpException('Page not found!');
  135.                         }
  136.                         break;
  137.                 }
  138.                 break;
  139.             default:
  140.                 throw new NotFoundHttpException('Page not found!');
  141.         }
  142.         $quickActionButtonCollection->prepareAssets();
  143.         return $this->render('@UVDeskCoreFramework//ticket.html.twig', [
  144.             'ticket' => $ticket,
  145.             'totalReplies' => $ticketRepository->countTicketTotalThreads($ticket->getId()),
  146.             'totalCustomerTickets' => ($ticketRepository->countCustomerTotalTickets($customer$container) - 1),
  147.             'initialThread' => $this->ticketService->getTicketInitialThreadDetails($ticket),
  148.             'ticketAgent' => !empty($agent) ? $agent->getAgentInstance()->getPartialDetails() : null,
  149.             'customer' => $customer->getCustomerInstance()->getPartialDetails(),
  150.             'currentUserDetails' => $user->getAgentInstance()->getPartialDetails(),
  151.             'supportGroupCollection' => $userRepository->getSupportGroups(),
  152.             'supportTeamCollection' => $userRepository->getSupportTeams(),
  153.             'ticketStatusCollection' => $entityManager->getRepository(TicketStatus::class)->findAll(),
  154.             'ticketTypeCollection' => $entityManager->getRepository(TicketType::class)->findByIsActive(true),
  155.             'ticketPriorityCollection' => $entityManager->getRepository(TicketPriority::class)->findAll(),
  156.             'ticketNavigationIteration' => $ticketRepository->getTicketNavigationIteration($ticket$container),
  157.             'ticketLabelCollection' => $ticketRepository->getTicketLabelCollection($ticket$user),
  158.         ]);
  159.     }
  160.     public function saveTicket(Request $request)
  161.     {
  162.         $requestParams $request->request->all();
  163.         $entityManager $this->getDoctrine()->getManager();
  164.         $response $this->redirect($this->generateUrl('helpdesk_member_ticket_collection'));
  165.         if ($request->getMethod() != 'POST' || false == $this->userService->isAccessAuthorized('ROLE_AGENT_CREATE_TICKET')) {
  166.             return $response;
  167.         }
  168.         // Get referral ticket if any
  169.         $ticketValidationGroup 'CreateTicket';
  170.         $referralURL $request->headers->get('referer');
  171.         if (!empty($referralURL)) {
  172.             $iterations explode('/'$referralURL);
  173.             $referralId array_pop($iterations);
  174.             $expectedReferralURL $this->generateUrl('helpdesk_member_ticket', ['ticketId' => $referralId], UrlGeneratorInterface::ABSOLUTE_URL);
  175.             if ($referralURL === $expectedReferralURL) {
  176.                 $referralTicket $entityManager->getRepository(CoreBundleTicket::class)->findOneById($referralId);
  177.                 if (!empty($referralTicket)) {
  178.                     $ticketValidationGroup 'CustomerCreateTicket';
  179.                 }
  180.             }
  181.         }
  182.         $ticketType $entityManager->getRepository(TicketType::class)->findOneById($requestParams['type']);
  183.         extract($this->customFieldsService->customFieldsValidation($request'user'));
  184.         if(!empty($errorFlashMessage)) {
  185.             $this->addFlash('warning'$errorFlashMessage);
  186.         }
  187.         $ticketProxy = new CoreFrameworkBundleDataProxies\CreateTicketDataClass();
  188.         $form $this->createForm(CoreFrameworkBundleForms\CreateTicket::class, $ticketProxy);
  189.         // Validate Ticket Details
  190.         $form->submit($requestParams);
  191.         if (false == $form->isSubmitted() || false == $form->isValid()) {
  192.             if (false === $form->isValid()) {
  193.                 // @TODO: We need to handle form errors gracefully.
  194.                 // We should also look into switching to an xhr request instead.
  195.                 // $form->getErrors(true);
  196.             }
  197.             return $this->redirect(!empty($referralURL) ? $referralURL $this->generateUrl('helpdesk_member_ticket_collection'));
  198.         }
  199.         if ('CustomerCreateTicket' === $ticketValidationGroup && !empty($referralTicket)) {
  200.             // Retrieve customer details from referral ticket
  201.             $customer $referralTicket->getCustomer();
  202.             $customerPartialDetails $customer->getCustomerInstance()->getPartialDetails();
  203.         } else if (null != $ticketProxy->getFrom() && null != $ticketProxy->getName()) {
  204.             // Create customer if account does not exists
  205.             $customer $entityManager->getRepository(User::class)->findOneByEmail($ticketProxy->getFrom());
  206.             if (empty($customer) || null == $customer->getCustomerInstance()) {
  207.                 $role $entityManager->getRepository(SupportRole::class)->findOneByCode('ROLE_CUSTOMER');
  208.                 // Create User Instance
  209.                 $customer $this->userService->createUserInstance($ticketProxy->getFrom(), $ticketProxy->getName(), $role, [
  210.                     'source' => 'website',
  211.                     'active' => true
  212.                 ]);
  213.             }
  214.         }
  215.         $ticketData = [
  216.             'from' => $customer->getEmail(),
  217.             'name' => $customer->getFirstName() . ' ' $customer->getLastName(),
  218.             'type' => $ticketProxy->getType(),
  219.             'subject' => $ticketProxy->getSubject(),
  220.             // @TODO: We need to enable support for html messages. 
  221.             // Our focus here instead should be to prevent XSS (filter js)
  222.             'message' => str_replace(['&lt;script&gt;''&lt;/script&gt;'], ''htmlspecialchars($ticketProxy->getReply())),
  223.             'firstName' => $customer->getFirstName(),
  224.             'lastName' => $customer->getLastName(),
  225.             'type' => $ticketProxy->getType(),
  226.             'role' => 4,
  227.             'source' => 'website',
  228.             'threadType' => 'create',
  229.             'createdBy' => 'agent',
  230.             'customer' => $customer,
  231.             'user' => $this->getUser(),
  232.             'attachments' => $request->files->get('attachments'),
  233.         ];
  234.         $thread $this->ticketService->createTicketBase($ticketData);
  235.         // Trigger ticket created event
  236.         try {
  237.             $event = new GenericEvent(CoreWorkflowEvents\Ticket\Create::getId(), [
  238.                 'entity' =>  $thread->getTicket(),
  239.             ]);
  240.             $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute', );
  241.         } catch (\Exception $e) {
  242.             // Skip Automation
  243.         }
  244.         if (!empty($thread)) {
  245.             $ticket $thread->getTicket();
  246.             if($request->request->get('customFields') || $request->files->get('customFields')) {
  247.                 $this->ticketService->addTicketCustomFields($thread$request->request->get('customFields'), $request->files->get('customFields'));                        
  248.             }
  249.             $this->addFlash('success'$this->translator->trans('Success ! Ticket has been created successfully.'));
  250.             if ($this->userService->isAccessAuthorized('ROLE_ADMIN')) {
  251.                 return $this->redirect($this->generateUrl('helpdesk_member_ticket', ['ticketId' => $ticket->getId()]));
  252.             }
  253.         } else {
  254.             $this->addFlash('warning'$this->translator->trans('Could not create ticket, invalid details.'));
  255.         }
  256.         return $this->redirect(!empty($referralURL) ? $referralURL $this->generateUrl('helpdesk_member_ticket_collection'));
  257.     }
  258.     public function listTicketTypeCollection(Request $request)
  259.     {
  260.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  261.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  262.         }
  263.         return $this->render('@UVDeskCoreFramework/ticketTypeList.html.twig');
  264.     }
  265.     public function ticketType(Request $request)
  266.     {
  267.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  268.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  269.         }
  270.         $errorContext = [];
  271.         $em $this->getDoctrine()->getManager();
  272.         if($id $request->attributes->get('ticketTypeId')) {
  273.             $type $em->getRepository(TicketType::class)->find($id);
  274.             if (!$type) {
  275.                 $this->noResultFound();
  276.             }
  277.         } else {
  278.             $type = new CoreFrameworkBundleEntities\TicketType();
  279.         }
  280.         if ($request->getMethod() == "POST") {
  281.             $data $request->request->all();
  282.             $ticketType $em->getRepository(TicketType::class)->findOneByCode($data['code']);
  283.             if (!empty($ticketType) && $id != $ticketType->getId()) {
  284.                 $this->addFlash('warning'sprintf('Error! Ticket type with same name already exist'));
  285.             } else {
  286.                 $type->setCode($data['code']);
  287.                 $type->setDescription($data['description']);
  288.                 $type->setIsActive(isset($data['isActive']) ? 0);
  289.                 $em->persist($type);
  290.                 $em->flush();
  291.                 if (!$request->attributes->get('ticketTypeId')) {
  292.                     $this->addFlash('success'$this->translator->trans('Success! Ticket type saved successfully.'));
  293.                 } else {
  294.                     $this->addFlash('success'$this->translator->trans('Success! Ticket type updated successfully.'));
  295.                 }
  296.                 return $this->redirect($this->generateUrl('helpdesk_member_ticket_type_collection'));
  297.             }
  298.         }
  299.         return $this->render('@UVDeskCoreFramework/ticketTypeAdd.html.twig', array(
  300.             'type' => $type,
  301.             'errors' => json_encode($errorContext)
  302.         ));
  303.     }
  304.     public function listTagCollection(Request $request)
  305.     {
  306.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TAG')) {
  307.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  308.         }
  309.         $enabled_bundles $this->getParameter('kernel.bundles');
  310.         return $this->render('@UVDeskCoreFramework/supportTagList.html.twig', [
  311.             'articlesEnabled' => in_array('UVDeskSupportCenterBundle'array_keys($enabled_bundles)),
  312.         ]);
  313.     }
  314.     public function removeTicketTagXHR($tagIdRequest $request)
  315.     {
  316.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TAG')) {
  317.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  318.         }
  319.         $json = [];
  320.         if($request->getMethod() == "DELETE") {
  321.             $em $this->getDoctrine()->getManager();
  322.             $tag $em->getRepository(Tag::class)->find($tagId);
  323.             if($tag) {
  324.                 $em->remove($tag);
  325.                 $em->flush();
  326.                 $json['alertClass'] = 'success';
  327.                 $json['alertMessage'] = $this->translator->trans('Success ! Tag removed successfully.');
  328.             }
  329.         }
  330.         $response = new Response(json_encode($json));
  331.         $response->headers->set('Content-Type''application/json');
  332.         return $response;
  333.     }
  334.     public function trashTicket(Request $request)
  335.     {
  336.         $ticketId $request->attributes->get('ticketId');
  337.         $entityManager $this->getDoctrine()->getManager();
  338.         $ticket $entityManager->getRepository(CoreBundleTicket::class)->find($ticketId);
  339.         if (!$ticket) {
  340.             $this->noResultFound();
  341.         }
  342.         $user $this->userService->getSessionUser();
  343.         // Proceed only if user has access to the resource
  344.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  345.             throw new \Exception('Access Denied'403);
  346.         }
  347.         if (!$ticket->getIsTrashed()) {
  348.             $ticket->setIsTrashed(1);
  349.             $entityManager->persist($ticket);
  350.             $entityManager->flush();
  351.         }
  352.         // Trigger ticket delete event
  353.         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Delete::getId(), [
  354.             'entity' => $ticket,
  355.         ]);
  356.         $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  357.         $this->addFlash('success'$this->translator->trans('Success ! Ticket moved to trash successfully.'));
  358.         return $this->redirectToRoute('helpdesk_member_ticket_collection');
  359.     }
  360.     // Delete a ticket ticket permanently
  361.     public function deleteTicket(Request $request)
  362.     {
  363.         $ticketId $request->attributes->get('ticketId');
  364.         $entityManager $this->getDoctrine()->getManager();
  365.         $ticket $entityManager->getRepository(CoreBundleTicket::class)->find($ticketId);
  366.         if (!$ticket) {
  367.             $this->noResultFound();
  368.         }
  369.         $user $this->userService->getSessionUser();
  370.         // Proceed only if user has access to the resource
  371.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  372.             throw new \Exception('Access Denied'403);
  373.         }
  374.         $entityManager->remove($ticket);
  375.         $entityManager->flush();
  376.         $this->addFlash('success'$this->translator->trans('Success ! Success ! Ticket Id #'$ticketId .' has been deleted successfully.'));
  377.         return $this->redirectToRoute('helpdesk_member_ticket_collection');
  378.     }
  379.     public function downloadZipAttachment(Request $request)
  380.     {
  381.         $threadId $request->attributes->get('threadId');
  382.         $attachmentRepository $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  383.         $threadRepository $this->getDoctrine()->getManager()->getRepository(Thread::class);
  384.         $thread $threadRepository->findOneById($threadId);
  385.         $attachment $attachmentRepository->findByThread($threadId);
  386.         if (!$attachment) {
  387.             $this->noResultFound();
  388.         }
  389.         $ticket $thread->getTicket();
  390.         $user $this->userService->getSessionUser();
  391.         
  392.         // Proceed only if user has access to the resource
  393.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  394.             throw new \Exception('Access Denied'403);
  395.         }
  396.         $zipname 'attachments/' .$threadId.'.zip';
  397.         $zip = new \ZipArchive;
  398.         $zip->open($zipname\ZipArchive::CREATE);
  399.         if (count($attachment)) {
  400.             foreach ($attachment as $attach) {
  401.                 $zip->addFile(substr($attach->getPath(), 1));
  402.             }
  403.         }
  404.         $zip->close();
  405.         $response = new Response();
  406.         $response->setStatusCode(200);
  407.         $response->headers->set('Content-type''application/zip');
  408.         $response->headers->set('Content-Disposition''attachment; filename=' $threadId '.zip');
  409.         $response->sendHeaders();
  410.         $response->setContent(readfile($zipname));
  411.         return $response;
  412.     }
  413.     public function downloadAttachment(Request $request)
  414.     {   
  415.         $attachmentId $request->attributes->get('attachmendId');
  416.         $attachmentRepository $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  417.         $attachment $attachmentRepository->findOneById($attachmentId);
  418.         $baseurl $request->getScheme() . '://' $request->getHttpHost() . $request->getBasePath();
  419.         if (!$attachment) {
  420.             $this->noResultFound();
  421.         }
  422.         $ticket $attachment->getThread()->getTicket();
  423.         $user $this->userService->getSessionUser();
  424.         
  425.         // Proceed only if user has access to the resource
  426.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  427.             throw new \Exception('Access Denied'403);
  428.         }
  429.         $path $this->kernel->getProjectDir() . "/public/"$attachment->getPath();
  430.         $response = new Response();
  431.         $response->setStatusCode(200);
  432.         $response->headers->set('Content-type'$attachment->getContentType());
  433.         $response->headers->set('Content-Disposition''attachment; filename='$attachment->getName());
  434.         $response->headers->set('Content-Length'$attachment->getSize());
  435.         $response->sendHeaders();
  436.         $response->setContent(readfile($path));
  437.         return $response;
  438.     }
  439.     /**
  440.      * If customer is playing with url and no result is found then what will happen
  441.      * @return 
  442.      */
  443.     protected function noResultFound()
  444.     {
  445.         throw new NotFoundHttpException('Not Found!');
  446.     }
  447. }