vendor/uvdesk/support-center-bundle/Controller/Ticket.php line 74

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\SupportCenterBundle\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\EventDispatcher\EventDispatcherInterface;
  13. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  14. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  15. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  16. use Webkul\UVDesk\CoreFrameworkBundle\Entity as CoreEntities;
  17. use Webkul\UVDesk\CoreFrameworkBundle\Services as CoreServices;
  18. use Webkul\UVDesk\SupportCenterBundle\Entity as SupportEntities;
  19. use Webkul\UVDesk\SupportCenterBundle\Form\Ticket as TicketForm;
  20. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  21. class Ticket extends AbstractController
  22. {
  23.     private $userService;
  24.     private $eventDispatcher;
  25.     private $translator;
  26.     private $uvdeskService;
  27.     private $ticketService;
  28.     private $recaptchaService;
  29.     private $kernel;
  30.     private $em;
  31.     public function __construct(CoreServices\UserService $userServiceCoreServices\UVDeskService $uvdeskServiceEventDispatcherInterface $eventDispatcherTranslatorInterface $translatorCoreServices\TicketService $ticketServiceCoreServices\ReCaptchaService $recaptchaServiceKernelInterface $kernelEntityManagerInterface $entityManager)
  32.     {
  33.         $this->userService $userService;
  34.         $this->eventDispatcher $eventDispatcher;
  35.         $this->translator $translator;
  36.         $this->uvdeskService $uvdeskService;
  37.         $this->ticketService $ticketService;
  38.         $this->recaptchaService $recaptchaService;
  39.         $this->kernel $kernel;
  40.         $this->em $entityManager;
  41.     }
  42.     protected function isWebsiteActive()
  43.     {
  44.         $website $this->em->getRepository(CoreEntities\Website::class)->findOneByCode('knowledgebase');
  45.         if (! empty($website)) {
  46.             $knowledgebaseWebsite $this->em->getRepository(SupportEntities\KnowledgebaseWebsite::class)->findOneBy(['website' => $website->getId(), 'status' => 1]);
  47.             if (
  48.                 ! empty($knowledgebaseWebsite)
  49.                 && true == $knowledgebaseWebsite->getIsActive()
  50.             ) {
  51.                 return true;
  52.             }
  53.         }
  54.         $this->noResultFound();
  55.     }
  56.     /**
  57.      * If customer is playing with url and no result is found then what will happen
  58.      * @return
  59.      */
  60.     protected function noResultFound()
  61.     {
  62.         throw new NotFoundHttpException('Not found !');
  63.     }
  64.     public function ticketadd(Request $requestContainerInterface $container)
  65.     {
  66.         $this->isWebsiteActive();
  67.         $formErrors $errors = array();
  68.         $website $this->em->getRepository(CoreEntities\Website::class)->findOneByCode('knowledgebase');
  69.         $websiteConfiguration $this->uvdeskService->getActiveConfiguration($website->getId());
  70.         if (
  71.             ! $websiteConfiguration
  72.             || ! $websiteConfiguration->getTicketCreateOption()
  73.             || ($websiteConfiguration->getLoginRequiredToCreate()
  74.                 && ! $this->getUser())
  75.         ) {
  76.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  77.         }
  78.         $post $request->request->all();
  79.         $recaptchaDetails $this->recaptchaService->getRecaptchaDetails();
  80.         if ($request->getMethod() == "POST") {
  81.             if (
  82.                 $recaptchaDetails
  83.                 && $recaptchaDetails->getIsActive() == true
  84.                 && $this->recaptchaService->getReCaptchaResponse($request->request->get('g-recaptcha-response'))
  85.             ) {
  86.                 $this->addFlash('warning'$this->translator->trans("Warning ! Please select correct CAPTCHA !"));
  87.             } else {
  88.                 if ($_POST) {
  89.                     $error false;
  90.                     try {
  91.                         $customFieldsService null;
  92.                         if ($this->userService->isFileExists('apps/uvdesk/custom-fields')) {
  93.                             $customFieldsService $this->get('uvdesk_package_custom_fields.service');
  94.                         } else if ($this->userService->isFileExists('apps/uvdesk/form-component')) {
  95.                             $customFieldsService $this->get('uvdesk_package_form_component.service');
  96.                         }
  97.                         if (! empty($customFieldsService)) {
  98.                             if (
  99.                                 $request->files->get('customFields')
  100.                                 && ! $customFieldsService->validateAttachmentsSize($request->files->get('customFields'))
  101.                             ) {
  102.                                 $error true;
  103.                                 $this->addFlash(
  104.                                     'warning',
  105.                                     $this->translator->trans("Warning ! Files size can not exceed %size% MB", [
  106.                                         '%size%' => $this->getParameter('max_upload_size')
  107.                                     ])
  108.                                 );
  109.                             }
  110.                         }
  111.                     } catch (\Exception $e) {
  112.                         // @TODO: Log execption message
  113.                     }
  114.                     $ticket = new CoreEntities\Ticket();
  115.                     $loggedUser $this->get('security.token_storage')->getToken()->getUser();
  116.                     if (
  117.                         ! empty($loggedUser)
  118.                         && $loggedUser != 'anon.'
  119.                     ) {
  120.                         $form $this->createForm(TicketForm::class, $ticket, [
  121.                             'container'      => $container,
  122.                             'entity_manager' => $this->em,
  123.                         ]);
  124.                         $email $loggedUser->getEmail();
  125.                         try {
  126.                             $name $loggedUser->getFirstName() . ' ' $loggedUser->getLastName();
  127.                         } catch (\Exception $e) {
  128.                             $name explode(' 'strstr($email'@'true));
  129.                         }
  130.                     } else {
  131.                         $form $this->createForm(TicketForm::class, $ticket, [
  132.                             'container'      => $container,
  133.                             'entity_manager' => $this->em,
  134.                         ]);
  135.                         $email $request->request->get('from');
  136.                         $name explode(' '$request->request->get('name'));
  137.                     }
  138.                     $website $this->em->getRepository(CoreEntities\Website::class)->findOneByCode('knowledgebase');
  139.                     if (
  140.                         ! empty($email)
  141.                         && $this->ticketService->isEmailBlocked($email$website)
  142.                     ) {
  143.                         $request->getSession()->getFlashBag()->set('warning'$this->translator->trans('Warning ! Cannot create ticket, given email is blocked by admin.'));
  144.                         return $this->redirect($this->generateUrl('helpdesk_customer_create_ticket'));
  145.                     }
  146.                     if ($request->request->all())
  147.                         $form->submit($request->request->all());
  148.                     if ($form->isValid() && !count($formErrors) && !$error) {
  149.                         $data = array(
  150.                             'from'      => $email,
  151.                             'subject'   => $request->request->get('subject'),
  152.                             'reply'     => str_replace(['&lt;script&gt;''&lt;/script&gt;'], ''htmlspecialchars($request->request->get('reply'))),
  153.                             'firstName' => $name[0],
  154.                             'lastName'  => isset($name[1]) ? $name[1] : '',
  155.                             'role'      => 4,
  156.                             'active'    => true
  157.                         );
  158.                         $data['type'] = $this->em->getRepository(CoreEntities\TicketType::class)->find($request->request->get('type'));
  159.                         if (! is_object($data['customer'] = $this->container->get('security.token_storage')->getToken()->getUser()) == "anon.") {
  160.                             $supportRole $this->em->getRepository(CoreEntities\SupportRole::class)->findOneByCode("ROLE_CUSTOMER");
  161.                             $customerEmail $params['email'] = $request->request->get('from');
  162.                             $customer $this->em->getRepository(CoreEntities\User::class)->findOneBy(array('email' => $customerEmail));
  163.                             $params['flag'] = (!$customer) ? 0;
  164.                             $data['firstName'] = current($nameDetails explode(' '$request->request->get('name')));
  165.                             $data['fullname'] = $request->request->get('name');
  166.                             $data['lastName'] = ($data['firstName'] != end($nameDetails)) ? end($nameDetails) : " ";
  167.                             $data['from'] = $customerEmail;
  168.                             $data['role'] = 4;
  169.                             $data['customer'] = $this->userService->createUserInstance($customerEmail$data['fullname'], $supportRole$extras = ["active" => true]);
  170.                         } else {
  171.                             $userDetail $this->em->getRepository(CoreEntities\User::class)->find($data['customer']->getId());
  172.                             $data['email'] = $customerEmail $data['customer']->getEmail();
  173.                             $nameCollection = [$userDetail->getFirstName(), $userDetail->getLastName()];
  174.                             $name implode(' '$nameCollection);
  175.                             $data['fullname'] = $name;
  176.                         }
  177.                         $data['user'] = $data['customer'];
  178.                         $data['subject'] = $request->request->get('subject');
  179.                         $data['source'] = 'website';
  180.                         $data['threadType'] = 'create';
  181.                         $data['message'] = $data['reply'];
  182.                         $data['createdBy'] = 'customer';
  183.                         $data['attachments'] = $request->files->get('attachments');
  184.                         if (! empty($request->server->get("HTTP_CF_CONNECTING_IP"))) {
  185.                             $data['ipAddress'] = $request->server->get("HTTP_CF_CONNECTING_IP");
  186.                             if (!empty($request->server->get("HTTP_CF_IPCOUNTRY"))) {
  187.                                 $data['ipAddress'] .= '(' $request->server->get("HTTP_CF_IPCOUNTRY") . ')';
  188.                             }
  189.                         }
  190.                         $thread $this->ticketService->createTicketBase($data);
  191.                         if (! empty($thread)) {
  192.                             $ticket $thread->getTicket();
  193.                             if (
  194.                                 $request->request->get('customFields')
  195.                                 || $request->files->get('customFields')
  196.                             ) {
  197.                                 $this->ticketService->addTicketCustomFields($thread$request->request->get('customFields'), $request->files->get('customFields'));
  198.                             }
  199.                             $this->addFlash('success'$this->translator->trans('Success ! Ticket has been created successfully.'));
  200.                         } else {
  201.                             $this->addFlash('warning'$this->translator->trans('Warning ! Can not create ticket, invalid details.'));
  202.                         }
  203.                         // Trigger ticket created event
  204.                         $event = new CoreWorkflowEvents\Ticket\Create();
  205.                         $event
  206.                             ->setTicket($thread->getTicket());
  207.                         $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  208.                         return null != $this->getUser() ? $this->redirect($this->generateUrl('helpdesk_customer_ticket_collection')) : $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  209.                     } else {
  210.                         $errors $this->getFormErrors($form);
  211.                         $errors array_merge($errors$formErrors);
  212.                     }
  213.                 } else {
  214.                     $this->addFlash(
  215.                         'warning',
  216.                         $this->translator->trans("Warning ! Post size can not exceed 25MB")
  217.                     );
  218.                 }
  219.                 if (
  220.                     isset($errors)
  221.                     && count($errors)
  222.                 ) {
  223.                     $this->addFlash('warning'key($errors) . ': ' reset($errors));
  224.                 }
  225.             }
  226.         }
  227.         $breadcrumbs = [
  228.             [
  229.                 'label' => $this->translator->trans('Support Center'),
  230.                 'url'   => $this->generateUrl('helpdesk_knowledgebase')
  231.             ],
  232.             [
  233.                 'label' => $this->translator->trans("Create Ticket Request"),
  234.                 'url'   => '#'
  235.             ],
  236.         ];
  237.         return $this->render(
  238.             '@UVDeskSupportCenter/Knowledgebase/ticket.html.twig',
  239.             array(
  240.                 'formErrors'         => $formErrors,
  241.                 'errors'             => json_encode($errors),
  242.                 'customFieldsValues' => $request->request->get('customFields'),
  243.                 'breadcrumbs'        => $breadcrumbs,
  244.                 'post'               => $post
  245.             )
  246.         );
  247.     }
  248.     public function saveReply(int $idRequest $request)
  249.     {
  250.         $this->isWebsiteActive();
  251.         $data $request->request->all();
  252.         $ticket $this->em->getRepository(CoreEntities\Ticket::class)->find($id);
  253.         $user $this->userService->getSessionUser();
  254.         // process only if access for the resource.
  255.         if (empty($ticket) || ((!empty($user)) && $user->getId() != $ticket->getCustomer()->getId())) {
  256.             if (! $this->isCollaborator($ticket$user)) {
  257.                 throw new \Exception('Access Denied'403);
  258.             }
  259.         }
  260.         if ($_POST) {
  261.             if (str_replace(' '''str_replace('&nbsp;'''trim(strip_tags($data['message'], '<img>')))) != "") {
  262.                 if (!$ticket)
  263.                     $this->noResultFound();
  264.                 $data['ticket'] = $ticket;
  265.                 $data['user'] = $this->userService->getCurrentUser();
  266.                 // Checking if reply is from collaborator end
  267.                 $isTicketCollaborator $ticket->getCollaborators() ? $ticket->getCollaborators()->toArray() : [];
  268.                 $isCollaborator false;
  269.                 foreach ($isTicketCollaborator as $value) {
  270.                     if ($value->getId() == $data['user']->getId()) {
  271.                         $isCollaborator true;
  272.                     }
  273.                 }
  274.                 // @TODO: Refactor -> Why are we filtering only these two characters?
  275.                 $data['message'] = str_replace(['&lt;script&gt;''&lt;/script&gt;'], ''htmlspecialchars($data['message']));
  276.                 $userDetail $this->userService->getCustomerPartialDetailById($data['user']->getId());
  277.                 $data['fullname'] = $userDetail['name'];
  278.                 $data['source'] = 'website';
  279.                 $data['createdBy'] = $isCollaborator 'collaborator' 'customer';
  280.                 $data['attachments'] = $request->files->get('attachments');
  281.                 $thread $this->ticketService->createThread($ticket$data);
  282.                 $status $this->em->getRepository(CoreEntities\TicketStatus::class)->findOneByCode($data['status']);
  283.                 if ($status) {
  284.                     $ticket
  285.                         ->setStatus($status);
  286.                     $this->em->persist($ticket);
  287.                 }
  288.                 $ticket->setCustomerRepliedAt(new \DateTime('now'));
  289.                 $this->em->persist($ticket);
  290.                 $this->em->flush();
  291.                 if ($thread->getcreatedBy() == 'customer') {
  292.                     $event = new CoreWorkflowEvents\Ticket\CustomerReply();
  293.                     $event
  294.                         ->setTicket($ticket)
  295.                         ->setThread($thread)
  296.                     ;
  297.                 } else {
  298.                     $event = new CoreWorkflowEvents\Ticket\CollaboratorReply();
  299.                     $event
  300.                         ->setTicket($ticket)
  301.                         ->setThread($thread)
  302.                     ;
  303.                 }
  304.                 $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  305.                 $this->eventDispatcher->dispatch($event'uvdesk.automation.report_app.workflow.execute');
  306.                 $this->addFlash('success'$this->translator->trans('Success ! Reply added successfully.'));
  307.             } else {
  308.                 $this->addFlash('warning'$this->translator->trans('Warning ! Reply field can not be blank.'));
  309.             }
  310.         } else {
  311.             $this->addFlash('warning'$this->translator->trans('Warning ! Post size can not exceed 25MB'));
  312.         }
  313.         return $this->redirect($this->generateUrl('helpdesk_customer_ticket', array(
  314.             'id' => $ticket->getId()
  315.         )));
  316.     }
  317.     public function tickets(Request $request)
  318.     {
  319.         $this->isWebsiteActive();
  320.         // List Announcement if any
  321.         $announcements =  $this->em->getRepository(SupportEntities\Announcement::class)->findBy(['isActive' => 1]);
  322.         $groupAnnouncement = [];
  323.         foreach ($announcements as $announcement) {
  324.             $announcementGroupId $announcement->getGroup();
  325.             $isTicketExist =  $this->em->getRepository(CoreEntities\Ticket::class)->findBy(['supportGroup' => $announcementGroupId'customer' => $this->userService->getCurrentUser()]);
  326.             if (! empty($isTicketExist)) {
  327.                 $groupAnnouncement[] = $announcement;
  328.             }
  329.         }
  330.         return $this->render(
  331.             '@UVDeskSupportCenter/Knowledgebase/ticketList.html.twig',
  332.             array(
  333.                 'searchDisable'     => true,
  334.                 'groupAnnouncement' => $groupAnnouncement
  335.             )
  336.         );
  337.     }
  338.     /**
  339.      * ticketListXhrAction "Filter and sort ticket collection on ajax request"
  340.      * @param Object $request "HTTP Request object"
  341.      * @return JSON "JSON response"
  342.      */
  343.     public function ticketListXhr(Request $requestContainerInterface $container)
  344.     {
  345.         $this->isWebsiteActive();
  346.         $json = array();
  347.         if ($request->isXmlHttpRequest()) {
  348.             $repository $this->em->getRepository(CoreEntities\Ticket::class);
  349.             $json $repository->getAllCustomerTickets($request->query$container);
  350.         }
  351.         $response = new Response(json_encode($json));
  352.         $response->headers->set('Content-Type''application/json');
  353.         return $response;
  354.     }
  355.     /**
  356.      * threadListXhrAction "Filter and sort user collection on ajx request"
  357.      * @param Object $request "HTTP Request object"
  358.      * @return JSON "JSON response"
  359.      */
  360.     public function threadListXhr(Request $requestContainerInterface $container)
  361.     {
  362.         $this->isWebsiteActive();
  363.         $json = array();
  364.         if ($request->isXmlHttpRequest()) {
  365.             $repository $this->em->getRepository(CoreEntities\Thread::class);
  366.             $json $repository->getAllCustomerThreads($request->attributes->get('id'), $request->query$container);
  367.         }
  368.         $response = new Response(json_encode($json));
  369.         $response->headers->set('Content-Type''application/json');
  370.         return $response;
  371.     }
  372.     public function ticketView($idRequest $request)
  373.     {
  374.         $this->isWebsiteActive();
  375.         $user $this->userService->getSessionUser();
  376.         $ticket $this->em->getRepository(CoreEntities\Ticket::class)->findOneBy(['id' => $id]);
  377.         $isConfirmColl false;
  378.         if ($ticket->getIsTrashed()) {
  379.             return $this->redirect($this->generateUrl('helpdesk_customer_ticket_collection'));
  380.         }
  381.         if ($ticket == null && empty($ticket)) {
  382.             throw new NotFoundHttpException('Page Not Found!');
  383.         }
  384.         if (
  385.             ! empty($ticket)
  386.             && ((!empty($user))
  387.                 && $user->getId() != $ticket->getCustomer()->getId())
  388.         ) {
  389.             if ($this->isCollaborator($ticket$user)) {
  390.                 $isConfirmColl true;
  391.             }
  392.             if ($isConfirmColl != true) {
  393.                 throw new \Exception('Access Denied'403);
  394.             }
  395.         }
  396.         if (
  397.             ! empty($user)
  398.             && $user->getId() == $ticket->getCustomer()->getId()
  399.         ) {
  400.             $ticket->setIsCustomerViewed(1);
  401.             $this->em->persist($ticket);
  402.             $this->em->flush();
  403.         }
  404.         $checkTicket $this->em->getRepository(CoreEntities\Ticket::class)->isTicketCollaborator($ticket$user->getEmail());
  405.         $twigResponse = [
  406.             'ticket'                => $ticket,
  407.             'searchDisable'         => true,
  408.             'initialThread'         => $this->ticketService->getTicketInitialThreadDetails($ticket),
  409.             'localizedCreateAtTime' => $this->userService->getLocalizedFormattedTime($ticket->getCreatedAt(), $user),
  410.             'isCollaborator'        => $checkTicket,
  411.         ];
  412.         return $this->render('@UVDeskSupportCenter/Knowledgebase/ticketView.html.twig'$twigResponse);
  413.     }
  414.     // Check if user is collaborator for the ticket
  415.     public function isCollaborator($ticket$user)
  416.     {
  417.         $isCollaborator false;
  418.         if (! empty($ticket->getCollaborators()->toArray())) {
  419.             foreach ($ticket->getCollaborators()->toArray() as $collaborator) {
  420.                 if ($collaborator->getId() == $user->getId()) {
  421.                     $isCollaborator true;
  422.                 }
  423.             }
  424.         }
  425.         return $isCollaborator;
  426.     }
  427.     // Ticket rating
  428.     public function rateTicket(Request $request)
  429.     {
  430.         $this->isWebsiteActive();
  431.         $json = array();
  432.         $data json_decode($request->getContent(), true);
  433.         $id $data['id'];
  434.         $count intval($data['rating']);
  435.         if ($count || $count 6) {
  436.             $customer $this->userService->getCurrentUser();
  437.             $ticket $this->em->getRepository(CoreEntities\Ticket::class)->findOneBy([
  438.                 'id'       => $id,
  439.                 'customer' => $customer
  440.             ]);
  441.             if (empty($ticket)) {
  442.                 $json['alertClass'] = 'danger';
  443.                 $json['alertMessage'] = $this->translator->trans('Warning ! Invalid rating.');
  444.                 $response = new Response(json_encode($json));
  445.                 $response->headers->set('Content-Type''application/json');
  446.                 return $response;
  447.             }
  448.             $rating $this->em->getRepository(CoreEntities\TicketRating::class)->findOneBy(array('ticket' => $id'customer' => $customer->getId()));
  449.             if ($rating) {
  450.                 $rating->setcreatedAt(new \DateTime);
  451.                 $rating->setStars($count);
  452.                 $this->em->persist($rating);
  453.                 $this->em->flush();
  454.             } else {
  455.                 $rating = new CoreEntities\TicketRating();
  456.                 $rating->setStars($count);
  457.                 $rating->setCustomer($customer);
  458.                 $rating->setTicket($ticket);
  459.                 $this->em->persist($rating);
  460.                 $this->em->flush();
  461.             }
  462.             $json['alertClass'] = 'success';
  463.             $json['alertMessage'] = $this->translator->trans('Success ! Rating has been successfully added.');
  464.         } else {
  465.             $json['alertClass'] = 'danger';
  466.             $json['alertMessage'] = $this->translator->trans('Warning ! Invalid rating.');
  467.         }
  468.         $response = new Response(json_encode($json));
  469.         $response->headers->set('Content-Type''application/json');
  470.         return $response;
  471.     }
  472.     public function downloadAttachmentZip(Request $request)
  473.     {
  474.         $threadId $request->attributes->get('threadId');
  475.         $attachmentRepository $this->em->getRepository(CoreEntities\Attachment::class);
  476.         $threadRepository $this->em->getRepository(CoreEntities\Thread::class);
  477.         // Get thread and attachments
  478.         $thread $threadRepository->findOneById($threadId);
  479.         $attachments $attachmentRepository->findByThread($threadId);
  480.         if (!$attachments) {
  481.             $this->noResultFound();
  482.         }
  483.         // Access control
  484.         $ticket $thread->getTicket();
  485.         $user $this->userService->getSessionUser();
  486.         if (
  487.             empty($ticket)
  488.             || (!empty($user) && $user->getId() != $ticket->getCustomer()->getId())
  489.         ) {
  490.             if (!$this->isCollaborator($ticket$user)) {
  491.                 throw new \Exception('Access Denied'403);
  492.             }
  493.         }
  494.         // Create ZIP file with proper path
  495.         $zipName sys_get_temp_dir() . '/attachments_' $threadId '.zip';
  496.         // Make sure directory exists
  497.         $zipDir dirname($zipName);
  498.         if (! file_exists($zipDir)) {
  499.             mkdir($zipDir0777true);
  500.         }
  501.         // Create new ZIP archive
  502.         $zip = new \ZipArchive();
  503.         if ($zip->open($zipName\ZipArchive::CREATE \ZipArchive::OVERWRITE) !== TRUE) {
  504.             throw new \Exception("Cannot create zip file");
  505.         }
  506.         // Add files to ZIP
  507.         foreach ($attachments as $attachment) {
  508.             $filePath substr($attachment->getPath(), 1); // Remove leading slash
  509.             if (file_exists($filePath)) {
  510.                 $zip->addFile($filePathbasename($filePath));
  511.             }
  512.         }
  513.         $zip->close();
  514.         // Check if file was created successfully
  515.         if (!file_exists($zipName)) {
  516.             throw new \Exception("ZIP file could not be created");
  517.         }
  518.         // Stream the file to prevent memory issues
  519.         $response = new BinaryFileResponse($zipName);
  520.         $response->headers->set('Content-Type''application/zip');
  521.         $response->headers->set('Content-Disposition'ResponseHeaderBag::DISPOSITION_ATTACHMENT '; filename="attachments_' $threadId '.zip"');
  522.         $response->deleteFileAfterSend(true); // Clean up after sending
  523.         return $response;
  524.     }
  525.     public function downloadAttachment(Request $request)
  526.     {
  527.         $attachmentId $request->attributes->get('attachmentId');
  528.         $attachment $this->em->getRepository(CoreEntities\Attachment::class)->findOneById($attachmentId);
  529.         if (empty($attachment)) {
  530.             $this->noResultFound();
  531.         }
  532.         $thread $attachment->getThread();
  533.         if (! empty($thread)) {
  534.             $ticket $thread->getTicket();
  535.             $user $this->userService->getSessionUser();
  536.             // process only if access for the resource.
  537.             if (
  538.                 empty($ticket)
  539.                 || ((! empty($user)) && $user->getId() != $ticket->getCustomer()->getId())
  540.             ) {
  541.                 if (! $this->isCollaborator($ticket$user)) {
  542.                     throw new \Exception('Access Denied'403);
  543.                 }
  544.             }
  545.         }
  546.         $path $this->kernel->getProjectDir() . "/public/" $attachment->getPath();
  547.         return new StreamedResponse(function () use ($path) {
  548.             readfile($path);
  549.         }, 200, [
  550.             'Content-Type'        => $attachment->getContentType(),
  551.             'Content-Disposition' => 'attachment; filename="' $attachment->getName() . '"',
  552.             'Content-Length'      => $attachment->getSize(),
  553.         ]);
  554.     }
  555.     public function ticketCollaboratorXhr(Request $request)
  556.     {
  557.         $json = array();
  558.         $content json_decode($request->getContent(), true);
  559.         $ticket $this->em->getRepository(CoreEntities\Ticket::class)->find($content['ticketId']);
  560.         $user $this->userService->getSessionUser();
  561.         // process only if access for the resource.
  562.         if (empty($ticket) || ((!empty($user)) && $user->getId() != $ticket->getCustomer()->getId())) {
  563.             if (! $this->isCollaborator($ticket$user)) {
  564.                 throw new \Exception('Access Denied'403);
  565.             }
  566.         }
  567.         if ($request->getMethod() == "POST") {
  568.             if ($content['email'] == $ticket->getCustomer()->getEmail()) {
  569.                 $json['alertClass'] = 'danger';
  570.                 $json['alertMessage'] = $this->translator->trans('Error ! Can not add customer as a collaborator.');
  571.             } else {
  572.                 $data = array(
  573.                     'from'      => $content['email'],
  574.                     'firstName' => ($firstName ucfirst(current(explode('@'$content['email'])))),
  575.                     'lastName'  => ' ',
  576.                     'role'      => 4,
  577.                 );
  578.                 $supportRole $this->em->getRepository(CoreEntities\SupportRole::class)->findOneByCode('ROLE_CUSTOMER');
  579.                 $collaborator $this->userService->createUserInstance($data['from'], $data['firstName'], $supportRole$extras = ["active" => true]);
  580.                 $checkTicket $this->em->getRepository(CoreEntities\Ticket::class)->isTicketCollaborator($ticket$content['email']);
  581.                 if (! $checkTicket) {
  582.                     $ticket->addCollaborator($collaborator);
  583.                     $this->em->persist($ticket);
  584.                     $this->em->flush();
  585.                     $ticket->lastCollaborator $collaborator;
  586.                     $collaborator $this->em->getRepository(CoreEntities\User::class)->find($collaborator->getId());
  587.                     $event = new CoreWorkflowEvents\Ticket\Collaborator();
  588.                     $event
  589.                         ->setTicket($ticket);
  590.                     $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  591.                     $json['collaborator'] =  $this->userService->getCustomerPartialDetailById($collaborator->getId());
  592.                     $json['alertClass'] = 'success';
  593.                     $json['alertMessage'] = $this->translator->trans('Success ! Collaborator added successfully.');
  594.                 } else {
  595.                     $json['alertClass'] = 'danger';
  596.                     $json['alertMessage'] = $this->translator->trans('Error ! Collaborator is already added.');
  597.                 }
  598.             }
  599.         } elseif ($request->getMethod() == "DELETE") {
  600.             $collaborator $this->em->getRepository(CoreEntities\User::class)->findOneBy(array('id' => $request->attributes->get('id')));
  601.             if ($collaborator) {
  602.                 $ticket->removeCollaborator($collaborator);
  603.                 $this->em->persist($ticket);
  604.                 $this->em->flush();
  605.                 $json['alertClass'] = 'success';
  606.                 $json['alertMessage'] = $this->translator->trans('Success ! Collaborator removed successfully.');
  607.             } else {
  608.                 $json['alertClass'] = 'danger';
  609.                 $json['alertMessage'] = $this->translator->trans('Error ! Invalid Collaborator.');
  610.             }
  611.         }
  612.         $response = new Response(json_encode($json));
  613.         $response->headers->set('Content-Type''application/json');
  614.         return $response;
  615.     }
  616.     public function ticketIntermediateAccess(Request $request)
  617.     {
  618.         $user $this->userService->getSessionUser();
  619.         $urid $request->query->get('urid');
  620.         $currentDateTime = new \DateTime('now', new \DateTimeZone('UTC'));
  621.         $resource $this->em->getRepository(CoreEntities\PublicResourceAccessLink::class)->findOneBy([
  622.             'uniqueResourceAccessId' => $urid,
  623.         ]);
  624.         $user $resource->getUser();
  625.         $website $this->em->getRepository(CoreEntities\Website::class)->findOneByCode('knowledgebase');
  626.         $websiteConfiguration $this->em->getRepository(SupportEntities\KnowledgebaseWebsite::class)->findOneBy(['website' => $website]);
  627.         if (empty($resource)) {
  628.             $this->addFlash('warning'$this->translator->trans("Invalid link."));
  629.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  630.         }
  631.         if (! empty($user)) {
  632.             if ($resource->getExpiresAt() < $currentDateTime || $websiteConfiguration->getPublicResourceAccessAttemptLimit() <= $resource->getTotalViews() || $resource->getIsExpired()) {
  633.                 $resource->setIsExpired(true);
  634.                 $this->em->persist($resource);
  635.                 $this->em->flush();
  636.                 $this->addFlash('warning'$this->translator->trans('Warning! Link expired or access limit reached.'));
  637.                 return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  638.             }
  639.             if ($resource->getResourceType() == CoreEntities\Ticket::class) {
  640.                 $ticket $this->em->getRepository(CoreEntities\Ticket::class)->findOneBy([
  641.                     'id' => (int) $resource->getResourceId(),
  642.                 ]);
  643.                 $session $request->getSession();
  644.                 $viewedLinks $session->get('accessed_public_links', []);
  645.                 $ticketId $ticket->getId();
  646.                 if (! in_array($ticketId$viewedLinks)) {
  647.                     $resource->setTotalViews($resource->getTotalViews() + 1);
  648.                     $this->em->persist($resource);
  649.                     $this->em->flush();
  650.                     $viewedLinks[] = $ticketId;
  651.                     $session->set('accessed_public_links'$viewedLinks);
  652.                 }
  653.                 $token = new UsernamePasswordToken($usernull'customer'$user->getRoles());
  654.                 $this->container->get('security.token_storage')->setToken($token);
  655.                 $request->getSession()->migrate();
  656.                 return $this->render('@UVDeskSupportCenter/Knowledgebase/ticketViewPublic.html.twig', [
  657.                     'ticket'                => $ticket,
  658.                     'searchDisable'         => true,
  659.                     'initialThread'         => $this->ticketService->getTicketInitialThreadDetails($ticket),
  660.                     'localizedCreateAtTime' => $this->userService->getLocalizedFormattedTime($ticket->getCreatedAt(), $user),
  661.                     'isCollaborator'        => $this->em->getRepository(CoreEntities\Ticket::class)->isTicketCollaborator($ticket$user->getEmail()),
  662.                 ]);
  663.             }
  664.         }
  665.         $this->addFlash('warning'$this->translator->trans("Please login to continue."));
  666.         return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  667.     }
  668. }