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

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