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

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\CommunityPackages\UVDesk\CustomFields\Entity;
  7. use Webkul\UVDesk\CommunityPackages\UVDesk\CustomFields\Entity as CommunityPackageEntities;
  8. use Webkul\UVDesk\CoreFrameworkBundle\Form as CoreFrameworkBundleForms;
  9. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  10. use Webkul\UVDesk\AutomationBundle\Entity\Workflow;
  11. use Webkul\UVDesk\CoreFrameworkBundle\Entity as CoreFrameworkBundleEntities;
  12. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  13. use Webkul\UVDesk\CoreFrameworkBundle\DataProxies as CoreFrameworkBundleDataProxies;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  15. use Webkul\UVDesk\CoreFrameworkBundle\Tickets\QuickActionButtonCollection;
  16. use Webkul\UVDesk\CoreFrameworkBundle\Repository\TicketRepository;
  17. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  18. use Symfony\Contracts\Translation\TranslatorInterface;
  19. use Webkul\UVDesk\CoreFrameworkBundle\Services\UVDeskService;
  20. use Webkul\UVDesk\CoreFrameworkBundle\Services\TicketService;
  21. use Webkul\UVDesk\CoreFrameworkBundle\Services\EmailService;
  22. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  23. use Symfony\Component\HttpKernel\KernelInterface;
  24. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  25. use Symfony\Component\DependencyInjection\ContainerInterface;
  26. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Attachment;
  27. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Thread;
  28. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket as CoreBundleTicket;
  29. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Tag;
  30. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketType;
  31. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportRole;
  32. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  33. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketPriority;
  34. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketStatus;
  35. use Webkul\UVDesk\MailboxBundle\Services\MailboxService;
  36. use UVDesk\CommunityPackages\UVDesk\CustomFields\Services\CustomFieldsService;
  37. use Doctrine\DBAL\Connection;
  38. use Symfony\Component\HttpFoundation\JsonResponse;
  39. class Ticket extends AbstractController
  40. {
  41.     private $userService;
  42.     private $translator;
  43.     private $eventDispatcher;
  44.     private $ticketService;
  45.     private $emailService;
  46.     private $kernel;
  47.     private $customFieldsService;
  48.     public function __construct(UserService $userServiceTranslatorInterface $translatorTicketService $ticketServiceEmailService $emailServiceEventDispatcherInterface $eventDispatcherKernelInterface $kernel,CustomFieldsService $customFieldsService)
  49.     {
  50.         $this->userService $userService;
  51.         $this->emailService $emailService;
  52.         $this->translator $translator;
  53.         $this->ticketService $ticketService;
  54.         $this->eventDispatcher $eventDispatcher;
  55.         $this->kernel $kernel;
  56.         $this->customFieldsService $customFieldsService;
  57.     }
  58.     public function listTicketCollection(Request $requestMailboxService $mailboxService)
  59.     {
  60.         $entityManager $this->getDoctrine()->getManager();
  61.          $connection $entityManager->getConnection();
  62.         $ticketEntities $this->getDoctrine()->getRepository(CoreBundleTicket::class)->findAll();
  63.                 // Create an array to hold the IDs
  64.                 $allWorkflowData = [];
  65.         // Loop through each ticket
  66.         foreach ($ticketEntities as $ticket) {
  67.             $ticketId $ticket->getId();
  68.             // Retrieve the tags for the ticket
  69.             $tags $this->ticketService->getTicketTagsById($ticketId);
  70.             // Only proceed if tags exist
  71.             if (!empty($tags)) {
  72.                 $tagName $tags[0]['name'];
  73.                 
  74.                 // SQL query to fetch workflow data for this ticket
  75.                 $sql "
  76.                     SELECT 
  77.                     MIN(w.name) AS left_side, 
  78.                     MIN(w.wf_tag) AS center, 
  79.                     w.priority AS right_side,
  80.                     MIN(t.code) AS code,
  81.                     MIN(th.status_update) AS status_update
  82.                 FROM uv_workflow w
  83.                 LEFT JOIN uv_ticket_type t ON w.name = t.code
  84.                 LEFT JOIN uv_thread th ON t.id = th.type_id AND th.ticket_id = :ticketId
  85.                 WHERE w.wf_tag LIKE :tagName
  86.                 GROUP BY w.priority
  87.                 ORDER BY CAST(w.priority AS UNSIGNED) ASC
  88.                 LIMIT 0, 1000;
  89.                 ";
  90.                 $stmt $connection->prepare($sql);
  91.                 $stmt->execute(['ticketId' => $ticketId'tagName'  => $tagName]);
  92.                 // Fetch all matching rows for this ticket
  93.                 $workflowData $stmt->fetchAll();
  94.             } else {
  95.                 // If no tags, assign an empty array (so that it's defined)
  96.                 $workflowData = [];
  97.             }
  98.             // Save the workflow data for this ticket ID in the overall array
  99.             $allWorkflowData[$ticketId] = $workflowData;
  100.         }
  101.         $mailboxCollection = [];
  102.         $mailboxConfiguration $mailboxService->parseMailboxConfigurations();
  103.         
  104.         foreach ($mailboxConfiguration->getMailboxes() as $mailbox) {
  105.             $imapConfiguration $mailbox->getImapConfiguration();
  106.             if (!empty($imapConfiguration)) {
  107.                 $mailboxCollection[] = [
  108.                     'name' => $mailbox->getName(), 
  109.                     'email' => $imapConfiguration->getUsername(), 
  110.                 ];
  111.             }
  112.         }
  113.         return $this->render('@UVDeskCoreFramework//ticketList.html.twig', [
  114.             'mailboxCollection' => $mailboxCollection
  115.             'ticketStatusCollection' => $entityManager->getRepository(TicketStatus::class)->findAll(), 
  116.             'ticketTypeCollection' => $entityManager->getRepository(TicketType::class)->findByIsActive(true), 
  117.             'ticketPriorityCollection' => $entityManager->getRepository(TicketPriority::class)->findAll(), 
  118.             'allWorkflowData' => $allWorkflowData,
  119.         ]);
  120.     }
  121.     public function loadTicket($ticketIdQuickActionButtonCollection $quickActionButtonCollectionContainerInterface $container)
  122.     {
  123.         $entityManager $this->getDoctrine()->getManager();
  124.         $connection $entityManager->getConnection();
  125.         $userRepository $entityManager->getRepository(User::class);
  126.         $workflow $entityManager->getRepository(Workflow::class);
  127.         $ticketRepository $entityManager->getRepository(CoreBundleTicket::class);
  128.         $ticket $ticketRepository->findOneById($ticketId);
  129.         $tags $this->ticketService->getTicketTagsById($ticketId);
  130.         if (isset($tags[0]['name'])) {
  131.             $tagName $tags[0]['name'];
  132.         } else {
  133.             $tagName 'No Tag Available'// Handle it properly
  134.         }
  135.         //$tagName = $tags[0]->name;
  136.         
  137.         if (empty($ticket)) {
  138.             throw new NotFoundHttpException('Page not found!');
  139.         }
  140.         
  141.         $user $this->userService->getSessionUser();
  142.         $timeSpent $ticket->getTimeSpent();
  143.         if (!empty($tags)) {
  144.             $sql "
  145.                    SELECT 
  146.                     left_side,
  147.                     center,
  148.                     right_side,
  149.                     code,
  150.                     status_update,
  151.                     updated_at
  152.                 FROM (
  153.                     SELECT 
  154.                         w.name AS left_side,
  155.                         w.wf_tag AS center,
  156.                         w.priority AS right_side,
  157.                         t.code,
  158.                         th.status_update,
  159.                         th.updated_at,
  160.                         ROW_NUMBER() OVER (PARTITION BY w.priority ORDER BY th.updated_at DESC) AS rn
  161.                     FROM uv_workflow w
  162.                     LEFT JOIN uv_ticket_type t 
  163.                         ON w.name = t.code
  164.                     LEFT JOIN uv_thread th 
  165.                         ON t.id = th.type_id 
  166.                     AND th.ticket_id = :ticketId
  167.                     WHERE w.wf_tag LIKE :tagName
  168.                 ) sub
  169.                 WHERE rn = 1
  170.                 ORDER BY CAST(right_side AS UNSIGNED) ASC
  171.                 LIMIT 0, 1000;
  172.                 ";
  173.         $stmt $connection->prepare($sql);
  174.         $stmt->execute(['ticketId' => $ticketId'tagName'  => $tagName]);
  175.             
  176.             // Fetch all matching rows
  177.             $workflowData $stmt->fetchAll();
  178.         } else {
  179.             // If there are no tags available, handle accordingly
  180.             $workflowData null// or you could set it to an empty array []
  181.         }
  182.         
  183.         $sql "SELECT custom_field_id, value
  184.         FROM uv_pkg_uvdesk_form_component_ticket_custom_fields_values
  185.         WHERE ticket_id = :ticketId
  186.           AND thread_id IS NULL";
  187.         // Prepare the statement
  188.         $stmt $connection->prepare($sql);
  189.         // Execute the query with the bound ticket id
  190.         $stmt->execute([
  191.             ':ticketId' => $ticketId
  192.         ]);
  193.         // Fetch all matching rows as an associative array
  194.         $ticketcustomFields $stmt->fetchAll();
  195.         
  196.         // Proceed only if user has access to the resource
  197.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  198.             throw new \Exception('Access Denied'403);
  199.         }
  200.         $agent $ticket->getAgent();
  201.         $customer $ticket->getCustomer();
  202.      
  203.     if($agent != null && !empty($agent)){    
  204.         $ticketAssignAgent $agent->getId();
  205.         $currentUser $user->getId();
  206.     }
  207.         
  208.         // Mark as viewed by agents
  209.         if (false == $ticket->getIsAgentViewed()) {
  210.             $ticket->setIsAgentViewed(true);
  211.             $entityManager->persist($ticket);
  212.             $entityManager->flush();
  213.         }
  214.     
  215.         // Ticket Authorization
  216.         $supportRole $user->getCurrentInstance()->getSupportRole()->getCode(); 
  217.         switch($supportRole) {
  218.             case 'ROLE_ADMIN':
  219.             case 'ROLE_SUPER_ADMIN':
  220.                 break;
  221.             case 'ROLE_AGENT':
  222.                 $accessLevel = (int) $user->getCurrentInstance()->getTicketAccessLevel();
  223.                 switch($accessLevel) {
  224.                     case TicketRepository::TICKET_GLOBAL_ACCESS:
  225.                         break;
  226.                     case TicketRepository::TICKET_GROUP_ACCESS:
  227.                         $supportGroups array_map(function($supportGroup) { return $supportGroup->getId(); }, $user->getCurrentInstance()->getSupportGroups()->getValues());                       
  228.                         $ticketAccessableGroups $ticket->getSupportGroup() ? [$ticket->getSupportGroup()->getId()] : [];
  229.  
  230.                         if ($ticket->getSupportTeam()) {
  231.                             $ticketSupportTeamGroups array_map(function($supportGroup) { return $supportGroup->getId(); }, $ticket->getSupportTeam()->getSupportGroups()->getValues());
  232.                             $ticketAccessableGroups array_merge($ticketAccessableGroups$ticketSupportTeamGroups);
  233.                         }
  234.                         $isAccessableGroupFound false;
  235.                         foreach($ticketAccessableGroups as $groupId) {
  236.                             if (in_array($groupId$supportGroups)) {
  237.                                 $isAccessableGroupFound true;
  238.                                 break;
  239.                             }
  240.                         }
  241.                         if (!$isAccessableGroupFound && !($ticketAssignAgent == $currentUser)) {
  242.                             throw new NotFoundHttpException('Page not found!');
  243.                         }
  244.                         break;
  245.                     case TicketRepository::TICKET_TEAM_ACCESS:
  246.                         $supportTeams array_map(function($supportTeam) { return $supportTeam->getId(); }, $user->getCurrentInstance()->getSupportTeams()->getValues());                         
  247.                         $supportTeam $ticket->getSupportTeam();
  248.                         if (!($supportTeam && in_array($supportTeam->getId(), $supportTeams)) && !($ticketAssignAgent == $currentUser)) {
  249.                             throw new NotFoundHttpException('Page not found!');
  250.                         }
  251.                         break;
  252.                     default:
  253.                         $collaborators array_map( function ($collaborator) { return $collaborator->getId(); }, $ticket->getCollaborators()->getValues());
  254.                         $accessableAgents array_merge($collaborators$ticket->getAgent() ? [$ticket->getAgent()->getId()] : []);
  255.                         if (!in_array($user->getId(), $accessableAgents)) {
  256.                             throw new NotFoundHttpException('Page not found!');
  257.                         }
  258.                         break;
  259.                 }
  260.                 break;
  261.             default:
  262.                 throw new NotFoundHttpException('Page not found!');
  263.         }
  264.         $quickActionButtonCollection->prepareAssets();
  265.         
  266.         try {
  267.     if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  268.         $headerCustomFields $this->customFieldsService->getCustomFieldsArray('user');;
  269.     } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  270.         $headerCustomFields $this->customFieldsService->getCustomFieldsArray('user');;
  271.     }
  272. } catch (\Exception $e) {
  273.     // @TODO: Log execption message
  274. }
  275.         return $this->render('@UVDeskCoreFramework//ticket.html.twig', [
  276.             'ticket' => $ticket,
  277.             'timeSpent' => $timeSpent,
  278.             'totalReplies' => $ticketRepository->countTicketTotalThreads($ticket->getId()),
  279.             'totalCustomerTickets' => ($ticketRepository->countCustomerTotalTickets($customer$container) - 1),
  280.             'initialThread' => $this->ticketService->getTicketInitialThreadDetails($ticket),
  281.             'ticketAgent' => !empty($agent) ? $agent->getAgentInstance()->getPartialDetails() : null,
  282.             'customer' => $customer->getCustomerInstance()->getPartialDetails(),
  283.             'currentUserDetails' => $user->getAgentInstance()->getPartialDetails(),
  284.             'supportGroupCollection' => $userRepository->getSupportGroups(),
  285.             'supportTeamCollection' => $userRepository->getSupportTeams(),
  286.             'ticketStatusCollection' => $entityManager->getRepository(TicketStatus::class)->findAll(),
  287.             'ticketTypeCollection' => $entityManager->getRepository(TicketType::class)->findByIsActive(true),
  288.             'ticketPriorityCollection' => $entityManager->getRepository(TicketPriority::class)->findAll(),
  289.             'ticketNavigationIteration' => $ticketRepository->getTicketNavigationIteration($ticket$container),
  290.             'ticketLabelCollection' => $ticketRepository->getTicketLabelCollection($ticket$user),
  291.             'headerCustomFields' => $headerCustomFields ?? null,
  292.             'workflowData' => $workflowData,
  293.             'ticketcustomFields' => $ticketcustomFields,
  294.         ]);
  295.     }
  296.     
  297.      public function showWorkflow(Request $request): JsonResponse
  298.     {
  299.         $entityManager $this->getDoctrine()->getManager();
  300.         $connection $entityManager->getConnection();
  301.         $ticketId $request->query->get('ticketId'0); // 0 is the default if not provided
  302.         // Retrieve all workflow entities (adjust the method as needed)
  303.         $ticketRepository $entityManager->getRepository(CoreBundleTicket::class);
  304.         $ticket $ticketRepository->findOneById($ticketId);
  305.         $tags $this->ticketService->getTicketTagsById($ticketId);
  306.         $tagName $tags[0]['name'];
  307.         //$tagName = $tags[0]->name;
  308.         
  309.         if (empty($ticket)) {
  310.             throw new NotFoundHttpException('Page not found!');
  311.         }
  312.         
  313.         $user $this->userService->getSessionUser();
  314.         if (!empty($tags)) {
  315.             $sql "
  316.             SELECT 
  317.                 left_side,
  318.                 center,
  319.                 right_side,
  320.                 code,
  321.                 status_update,
  322.                 updated_at
  323.             FROM (
  324.                 SELECT 
  325.                     w.name AS left_side,
  326.                     w.wf_tag AS center,
  327.                     w.priority AS right_side,
  328.                     t.code,
  329.                     th.status_update,
  330.                     th.updated_at,
  331.                     ROW_NUMBER() OVER (PARTITION BY w.priority ORDER BY th.updated_at DESC) AS rn
  332.                 FROM uv_workflow w
  333.                 LEFT JOIN uv_ticket_type t 
  334.                     ON w.name = t.code
  335.                 LEFT JOIN uv_thread th 
  336.                     ON t.id = th.type_id 
  337.                 AND th.ticket_id = :ticketId
  338.                 WHERE w.wf_tag LIKE :tagName
  339.             ) sub
  340.             WHERE rn = 1
  341.             ORDER BY CAST(right_side AS UNSIGNED) ASC
  342.             LIMIT 0, 1000;
  343.         ";
  344.         $stmt $connection->prepare($sql);
  345.         $stmt->execute(['ticketId' => $ticketId'tagName'  => $tagName]);
  346.             
  347.             // Fetch all matching rows
  348.             $workflow $stmt->fetchAll();
  349.         } else {
  350.             // If there are no tags available, handle accordingly
  351.             $workflow null// or you could set it to an empty array []
  352.         }
  353.          // Define the SQL query with a join between uv_ticket and uv_ticket_type
  354.          $sql '
  355.          SELECT ut.code
  356.          FROM uv_ticket t
  357.          JOIN uv_ticket_type ut ON t.type_id = ut.id
  358.          WHERE t.id = :ticketId
  359.         ';
  360.         // Prepare and execute the query
  361.         $stmt $connection->prepare($sql);
  362.         $stmt->bindValue('ticketId'$ticketId);
  363.         $stmt->execute();
  364.         // Fetch the code (assuming there is only one result)
  365.         $code $stmt->fetchColumn();
  366.         // Combine workflow data and code into one response array
  367.         $response = [
  368.             'workflow' => $workflow,
  369.             'code'     => $code
  370.         ];
  371.         return new JsonResponse($response);
  372.         
  373.     }
  374.     
  375.     
  376.     public function fetchEmails(Request $requestConnection $connection) {
  377.         $entityManager $this->getDoctrine()->getManager();
  378.         $query $request->query->get('query');
  379.         // SQL query to fetch emails based on the input query
  380.         $sql "
  381.             SELECT u.email
  382.             FROM uv_user_instance ui
  383.             JOIN uv_user u ON ui.user_id = u.id
  384.             WHERE ui.supportRole_id IN (3, 4) AND u.email LIKE :query
  385.         ";
  386.         $statement $connection->prepare($sql);
  387.         $statement->execute(['query' => '%' $query '%']);
  388.         $emails $statement->fetchAll();
  389.         // Extract emails from the result
  390.         $emailList array_map(function($email) {
  391.             return $email['email'];
  392.         }, $emails);
  393.         return new JsonResponse($emailList);
  394.     }
  395.       public function getUserFullNames(Request $request): JsonResponse
  396.     {
  397.         // Obtain the Doctrine connection
  398.         $entityManager $this->getDoctrine()->getManager();
  399.         $connection $entityManager->getConnection();
  400.         $queryText $request->query->get('query''');
  401.         // Define the SQL query to combine first_name and last_name
  402.         $sql "
  403.             SELECT 
  404.                 CASE
  405.                     WHEN last_name IS NULL OR last_name = '' THEN first_name
  406.                     ELSE CONCAT(first_name, ' ', last_name)
  407.                 END AS full_name
  408.             FROM uv_user
  409.             WHERE 
  410.                 CASE
  411.                     WHEN last_name IS NULL OR last_name = '' THEN first_name
  412.                     ELSE CONCAT(first_name, ' ', last_name)
  413.                 END LIKE :query
  414.         ";
  415.     
  416.         // Prepare and execute the query without binding any parameters
  417.         $stmt $connection->prepare($sql);
  418.         $stmt->execute(['query' => '%' $queryText '%']);
  419.         // Fetch all results (each row will have a key 'full_name')
  420.         $fullNames $stmt->fetchAll();
  421.         // if (empty($fullNames)) {
  422.         //     $redirectUrl = $this->generateUrl('helpdesk_member_create_customer_account');
  423.         //     return new JsonResponse(['redirect' => $redirectUrl]);
  424.         // }
  425.         // Return the results as a JSON response
  426.         return new JsonResponse($fullNames);
  427.     }    
  428.     public function saveTicket(Request $request)
  429.     {
  430.         $requestParams $request->request->all();
  431.         $entityManager $this->getDoctrine()->getManager();
  432.         $response $this->redirect($this->generateUrl('helpdesk_member_ticket_collection'));
  433.         if ($request->getMethod() != 'POST' || false == $this->userService->isAccessAuthorized('ROLE_AGENT_CREATE_TICKET')) {
  434.             return $response;
  435.         }
  436.         // Get referral ticket if any
  437.         $ticketValidationGroup 'CreateTicket';
  438.         $referralURL $request->headers->get('referer');
  439.         if (!empty($referralURL)) {
  440.             $iterations explode('/'$referralURL);
  441.             $referralId array_pop($iterations);
  442.             $expectedReferralURL $this->generateUrl('helpdesk_member_ticket', ['ticketId' => $referralId], UrlGeneratorInterface::ABSOLUTE_URL);
  443.             if ($referralURL === $expectedReferralURL) {
  444.                 $referralTicket $entityManager->getRepository(CoreBundleTicket::class)->findOneById($referralId);
  445.                 if (!empty($referralTicket)) {
  446.                     $ticketValidationGroup 'CustomerCreateTicket';
  447.                 }
  448.             }
  449.         }
  450.         $ticketType $entityManager->getRepository(TicketType::class)->findOneById($requestParams['type']);
  451.         try {
  452.             if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  453.                 $customFieldsService $this->customFieldsService;
  454.             } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  455.                 $customFieldsService $this->customFieldsService;
  456.             }
  457.             if (!empty($customFieldsService)) {
  458.                 extract($customFieldsService->customFieldsValidation($request'user'));
  459.             }
  460.         } catch (\Exception $e) {
  461.             // @TODO: Log execption message
  462.         }
  463.         if(!empty($errorFlashMessage)) {
  464.             $this->addFlash('warning'$errorFlashMessage);
  465.         }
  466.         
  467.         $ticketProxy = new CoreFrameworkBundleDataProxies\CreateTicketDataClass();
  468.         $form $this->createForm(CoreFrameworkBundleForms\CreateTicket::class, $ticketProxy);
  469.         // Validate Ticket Details
  470.         $form->submit($requestParams);
  471.         if (false == $form->isSubmitted() || false == $form->isValid()) {
  472.             if (false === $form->isValid()) {
  473.                 // @TODO: We need to handle form errors gracefully.
  474.                 // We should also look into switching to an xhr request instead.
  475.                 // $form->getErrors(true);
  476.             }
  477.             return $this->redirect(!empty($referralURL) ? $referralURL $this->generateUrl('helpdesk_member_ticket_collection'));
  478.         }
  479.         if ('CustomerCreateTicket' === $ticketValidationGroup && !empty($referralTicket)) {
  480.             // Retrieve customer details from referral ticket
  481.             $customer $referralTicket->getCustomer();
  482.             $customerPartialDetails $customer->getCustomerInstance()->getPartialDetails();
  483.         } else if (null != $ticketProxy->getFrom() && null != $ticketProxy->getName()) {
  484.             // Create customer if account does not exists
  485.             $customer $entityManager->getRepository(User::class)->findOneByEmail($ticketProxy->getFrom());
  486.             if (empty($customer) || null == $customer->getCustomerInstance()) {
  487.                 $role $entityManager->getRepository(SupportRole::class)->findOneByCode('ROLE_CUSTOMER');
  488.                 // Create User Instance
  489.                 $customer $this->userService->createUserInstance($ticketProxy->getFrom(), $ticketProxy->getName(), $role, [
  490.                     'source' => 'website',
  491.                     'active' => true
  492.                 ]);
  493.             }
  494.         }
  495.         $ticketData = [
  496.             'from' => $customer->getEmail(),
  497.             'name' => $customer->getFirstName() . ' ' $customer->getLastName(),
  498.             'type' => $ticketProxy->getType(),
  499.             'subject' => $ticketProxy->getSubject(),
  500.             // @TODO: We need to enable support for html messages. 
  501.             // Our focus here instead should be to prevent XSS (filter js)
  502.             'message' => str_replace(['&lt;script&gt;''&lt;/script&gt;'], ''htmlspecialchars($ticketProxy->getReply())),
  503.             'firstName' => $customer->getFirstName(),
  504.             'lastName' => $customer->getLastName(),
  505.             'type' => $ticketProxy->getType(),
  506.             'role' => 4,
  507.             'source' => 'website',
  508.             'threadType' => 'create',
  509.             'createdBy' => 'agent',
  510.             'customer' => $customer,
  511.             'user' => $this->getUser(),
  512.             'attachments' => $request->files->get('attachments'),
  513.         ];
  514.         $thread $this->ticketService->createTicketBase($ticketData);
  515.         
  516.         if (!empty($thread)) {
  517.             $ticket $thread->getTicket();
  518.         
  519.             if ($request->request->get('customFields') || $request->files->get('customFields')) {
  520.                 $this->ticketService->addTicketCustomFields($thread$request->request->get('customFields'), $request->files->get('customFields'));                        
  521.             }
  522.         // Trigger ticket created event
  523.         try {
  524.             $event = new GenericEvent(CoreWorkflowEvents\Ticket\Create::getId(), [
  525.                 'entity' =>  $thread->getTicket(),
  526.                 'customfields' => $form->getExtraData(),
  527.             ]);
  528.             $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  529.         } catch (\Exception $e) {
  530.             //echo '1';// Skip Automation
  531.         }
  532.             $this->addFlash('success'$this->translator->trans('Success ! Ticket has been created successfully.'));
  533.             if ($this->userService->isAccessAuthorized('ROLE_ADMIN')) {
  534.                 return $this->redirect($this->generateUrl('helpdesk_member_ticket', ['ticketId' => $ticket->getId()]));
  535.             }
  536.         } else {
  537.             $this->addFlash('warning'$this->translator->trans('Could not create ticket, invalid details.'));
  538.         }
  539.         return $this->redirect(!empty($referralURL) ? $referralURL $this->generateUrl('helpdesk_member_ticket_collection'));
  540.     }
  541.     public function listTicketTypeCollection(Request $request)
  542.     {
  543.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  544.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  545.         }
  546.         return $this->render('@UVDeskCoreFramework/ticketTypeList.html.twig');
  547.     }
  548.     public function ticketType(Request $request)
  549.     {
  550.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  551.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  552.         }
  553.     
  554.         $errorContext = [];
  555.         $em $this->getDoctrine()->getManager();
  556.     
  557.         if ($id $request->attributes->get('ticketTypeId')) {
  558.             $type $em->getRepository(TicketType::class)->find($id);
  559.     
  560.             if (!$type) {
  561.                 $this->noResultFound();
  562.             }
  563.         } else {
  564.             $type = new CoreFrameworkBundleEntities\TicketType();
  565.         }
  566.     
  567.         if ($request->getMethod() == "POST") {
  568.             $data $request->request->all();
  569.             $ticketType $em->getRepository(TicketType::class)->findOneByCode($data['code']);
  570.     
  571.             if (!empty($ticketType) && $id != $ticketType->getId()) {
  572.                 $this->addFlash('warning'sprintf('Error! Ticket type with same name already exists'));
  573.             } else {
  574.                 $type->setCode($data['code']);
  575.                 $type->setDescription($data['description']);
  576.                 $type->setIsActive(isset($data['isActive']) ? 0);
  577.                 
  578.                 // âœ… Set Visibility Value (Default to '2' if not provided)
  579.                 $visibility = isset($data['visibility']) ? (int)$data['visibility'] : 2;
  580.                 $type->setVisibility($visibility);
  581.     
  582.                 $em->persist($type);
  583.                 $em->flush();
  584.     
  585.                 if (!$request->attributes->get('ticketTypeId')) {
  586.                     $this->addFlash('success'$this->translator->trans('Success! Ticket type saved successfully.'));
  587.                 } else {
  588.                     $this->addFlash('success'$this->translator->trans('Success! Ticket type updated successfully.'));
  589.                 }
  590.     
  591.                 return $this->redirect($this->generateUrl('helpdesk_member_ticket_type_collection'));
  592.             }
  593.         }
  594.     
  595.         return $this->render('@UVDeskCoreFramework/ticketTypeAdd.html.twig', [
  596.             'type' => $type,
  597.             'errors' => json_encode($errorContext)
  598.         ]);
  599.     }
  600.     public function listTagCollection(Request $request)
  601.     {
  602.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TAG')) {
  603.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  604.         }
  605.         $enabled_bundles $this->getParameter('kernel.bundles');
  606.         return $this->render('@UVDeskCoreFramework/supportTagList.html.twig', [
  607.             'articlesEnabled' => in_array('UVDeskSupportCenterBundle'array_keys($enabled_bundles)),
  608.         ]);
  609.     }
  610.     public function removeTicketTagXHR($tagIdRequest $request)
  611.     {
  612.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TAG')) {
  613.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  614.         }
  615.         $json = [];
  616.         if($request->getMethod() == "DELETE") {
  617.             $em $this->getDoctrine()->getManager();
  618.             $tag $em->getRepository(Tag::class)->find($tagId);
  619.             if($tag) {
  620.                 $em->remove($tag);
  621.                 $em->flush();
  622.                 $json['alertClass'] = 'success';
  623.                 $json['alertMessage'] = $this->translator->trans('Success ! Tag removed successfully.');
  624.             }
  625.         }
  626.         $response = new Response(json_encode($json));
  627.         $response->headers->set('Content-Type''application/json');
  628.         return $response;
  629.     }
  630.     public function trashTicket(Request $request)
  631.     {
  632.         $ticketId $request->attributes->get('ticketId');
  633.         $entityManager $this->getDoctrine()->getManager();
  634.         $ticket $entityManager->getRepository(CoreBundleTicket::class)->find($ticketId);
  635.         if (!$ticket) {
  636.             $this->noResultFound();
  637.         }
  638.         $user $this->userService->getSessionUser();
  639.         // Proceed only if user has access to the resource
  640.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  641.             throw new \Exception('Access Denied'403);
  642.         }
  643.         if (!$ticket->getIsTrashed()) {
  644.             $ticket->setIsTrashed(1);
  645.             $entityManager->persist($ticket);
  646.             $entityManager->flush();
  647.         }
  648.         // Trigger ticket delete event
  649.         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Delete::getId(), [
  650.             'entity' => $ticket,
  651.         ]);
  652.         $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  653.         $this->addFlash('success'$this->translator->trans('Success ! Ticket moved to trash successfully.'));
  654.         return $this->redirectToRoute('helpdesk_member_ticket_collection');
  655.     }
  656.     // Delete a ticket ticket permanently
  657.     public function deleteTicket(Request $request)
  658.     {
  659.         $ticketId $request->attributes->get('ticketId');
  660.         $entityManager $this->getDoctrine()->getManager();
  661.         $ticket $entityManager->getRepository(CoreBundleTicket::class)->find($ticketId);
  662.         if (!$ticket) {
  663.             $this->noResultFound();
  664.         }
  665.         $user $this->userService->getSessionUser();
  666.         // Proceed only if user has access to the resource
  667.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  668.             throw new \Exception('Access Denied'403);
  669.         }
  670.         $entityManager->remove($ticket);
  671.         $entityManager->flush();
  672.         $this->addFlash('success'$this->translator->trans('Success ! Success ! Ticket Id #'$ticketId .' has been deleted successfully.'));
  673.         return $this->redirectToRoute('helpdesk_member_ticket_collection');
  674.     }
  675.     public function downloadZipAttachment(Request $request)
  676.     {
  677.         $threadId $request->attributes->get('threadId');
  678.         $attachmentRepository $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  679.         $threadRepository $this->getDoctrine()->getManager()->getRepository(Thread::class);
  680.         $thread $threadRepository->findOneById($threadId);
  681.         $attachment $attachmentRepository->findByThread($threadId);
  682.         if (!$attachment) {
  683.             $this->noResultFound();
  684.         }
  685.         $ticket $thread->getTicket();
  686.         $user $this->userService->getSessionUser();
  687.         
  688.         // Proceed only if user has access to the resource
  689.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  690.             throw new \Exception('Access Denied'403);
  691.         }
  692.         $zipname 'attachments/' .$threadId.'.zip';
  693.         $zip = new \ZipArchive;
  694.         $zip->open($zipname\ZipArchive::CREATE);
  695.         if (count($attachment)) {
  696.             foreach ($attachment as $attach) {
  697.                 $zip->addFile(substr($attach->getPath(), 1));
  698.             }
  699.         }
  700.         $zip->close();
  701.         $response = new Response();
  702.         $response->setStatusCode(200);
  703.         $response->headers->set('Content-type''application/zip');
  704.         $response->headers->set('Content-Disposition''attachment; filename=' $threadId '.zip');
  705.         $response->sendHeaders();
  706.         $response->setContent(readfile($zipname));
  707.         return $response;
  708.     }
  709.     public function downloadAttachment(Request $request)
  710.     {   
  711.         $attachmentId $request->attributes->get('attachmendId');
  712.         $attachmentRepository $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  713.         $attachment $attachmentRepository->findOneById($attachmentId);
  714.         $baseurl $request->getScheme() . '://' $request->getHttpHost() . $request->getBasePath();
  715.         if (!$attachment) {
  716.             $this->noResultFound();
  717.         }
  718.         $ticket $attachment->getThread()->getTicket();
  719.         $user $this->userService->getSessionUser();
  720.         
  721.         // Proceed only if user has access to the resource
  722.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  723.             throw new \Exception('Access Denied'403);
  724.         }
  725.         $path $this->kernel->getProjectDir() . "/public/"$attachment->getPath();
  726.         $response = new Response();
  727.         $response->setStatusCode(200);
  728.         $response->headers->set('Content-type'$attachment->getContentType());
  729.         $response->headers->set('Content-Disposition''attachment; filename='$attachment->getName());
  730.         $response->headers->set('Content-Length'$attachment->getSize());
  731.         $response->sendHeaders();
  732.         $response->setContent(readfile($path));
  733.         return $response;
  734.     }
  735.     /**
  736.      * If customer is playing with url and no result is found then what will happen
  737.      * @return 
  738.      */
  739.     protected function noResultFound()
  740.     {
  741.         throw new NotFoundHttpException('Not Found!');
  742.     }
  743. }