vendor/uvdesk/core-framework/Controller/TicketXHR.php line 549

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\HttpFoundation\JsonResponse;
  7. use Symfony\Component\EventDispatcher\GenericEvent;
  8. use Symfony\Contracts\Translation\TranslatorInterface;
  9. use Symfony\Component\DependencyInjection\ContainerInterface;
  10. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  11. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  12. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  13. use Webkul\UVDesk\SupportCenterBundle\Entity\ArticleTags;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  15. use Webkul\UVDesk\CoreFrameworkBundle\Services\TicketService;
  16. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  17. use Webkul\UVDesk\CoreFrameworkBundle\Entity as CoreFrameworkBundleEntities;
  18. use Webkul\UVDesk\SupportCenterBundle\Entity\KnowledgebaseWebsite;
  19. class TicketXHR extends AbstractController
  20. {
  21. const TICKET_ACCESS_LEVEL = [
  22. 1 => 'GLOBAL ACCESS',
  23. 2 => 'GROUP ACCESS',
  24. 3 => 'TEAM ACCESS',
  25. 4 => 'INDIVIDUAL ACCESS',
  26. ];
  27. private $userService;
  28. private $translator;
  29. private $eventDispatcher;
  30. private $ticketService;
  31. private $entityManager;
  32. public function __construct(UserService $userService, TranslatorInterface $translator, TicketService $ticketService, EventDispatcherInterface $eventDispatcher, EntityManagerInterface $entityManager)
  33. {
  34. $this->userService = $userService;
  35. $this->translator = $translator;
  36. $this->ticketService = $ticketService;
  37. $this->eventDispatcher = $eventDispatcher;
  38. $this->entityManager = $entityManager;
  39. }
  40. public function loadTicketXHR($ticketId)
  41. {
  42. $entityManager = $this->entityManager;
  43. $request = $this->container->get('request_stack')->getCurrentRequest();
  44. }
  45. public function bookmarkTicketXHR()
  46. {
  47. $entityManager = $this->entityManager;
  48. $request = $this->container->get('request_stack')->getCurrentRequest();
  49. $requestContent = json_decode($request->getContent(), true);
  50. $ticket = $entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->findOneById($requestContent['id']);
  51. // Process only if user have ticket access
  52. if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
  53. throw new \Exception('Access Denied', 403);
  54. }
  55. if (! empty($ticket)) {
  56. $ticket->setIsStarred(!$ticket->getIsStarred());
  57. $entityManager->persist($ticket);
  58. $entityManager->flush();
  59. return new Response(json_encode(['alertClass' => 'success']), 200, ['Content-Type' => 'application/json']);
  60. }
  61. return new Response(json_encode([]), 404, ['Content-Type' => 'application/json']);
  62. }
  63. public function ticketLabelXHR(Request $request)
  64. {
  65. $method = $request->getMethod();
  66. $content = $request->getContent();
  67. $em = $this->entityManager;
  68. if ($method == "POST") {
  69. $data = json_decode($content, true);
  70. if ($data['name'] != "") {
  71. $label = new CoreFrameworkBundleEntities\SupportLabel();
  72. $label->setName($data['name']);
  73. $label->setUser($this->userService->getCurrentUser());
  74. if (isset($data['colorCode']))
  75. $label->setColorCode($data['colorCode']);
  76. $em->persist($label);
  77. $em->flush();
  78. $json['alertClass'] = 'success';
  79. $json['alertMessage'] = $this->translator->trans('Success ! Label created successfully.');
  80. $json['label'] = json_encode([
  81. 'id' => $label->getId(),
  82. 'name' => $label->getName(),
  83. 'colorCode' => $label->getColorCode(),
  84. 'labelUser' => $label->getUser()->getId(),
  85. ]);
  86. } else {
  87. $json['alertClass'] = 'danger';
  88. $json['alertMessage'] = $this->translator->trans('Error ! Label name can not be blank.');
  89. }
  90. } elseif ($method == "PUT") {
  91. $data = json_decode($content, true);
  92. $label = $em->getRepository(CoreFrameworkBundleEntities\SupportLabel::class)->findOneBy(array('id' => $request->attributes->get('ticketLabelId')));
  93. if ($label) {
  94. $label->setName($data['name']);
  95. if (! empty($data['colorCode'])) {
  96. $label->setColorCode($data['colorCode']);
  97. }
  98. $em->persist($label);
  99. $em->flush();
  100. $json['label'] = json_encode([
  101. 'id' => $label->getId(),
  102. 'name' => $label->getName(),
  103. 'colorCode' => $label->getColorCode(),
  104. 'labelUser' => $label->getUser()->getId(),
  105. ]);
  106. $json['alertClass'] = 'success';
  107. $json['alertMessage'] = $this->translator->trans('Success ! Label updated successfully.');
  108. } else {
  109. $json['alertClass'] = 'danger';
  110. $json['alertMessage'] = $this->translator->trans('Error ! Invalid label id.');
  111. }
  112. } elseif ($method == "DELETE") {
  113. $label = $em->getRepository(CoreFrameworkBundleEntities\SupportLabel::class)->findOneBy(array('id' => $request->attributes->get('ticketLabelId')));
  114. if ($label) {
  115. $em->remove($label);
  116. $em->flush();
  117. $json['alertClass'] = 'success';
  118. $json['alertMessage'] = $this->translator->trans('Success ! Label removed successfully.');
  119. } else {
  120. $json['alertClass'] = 'danger';
  121. $json['alertMessage'] = $this->translator->trans('Error ! Invalid label id.');
  122. }
  123. }
  124. return new Response(json_encode($json), 200, ['Content-Type' => 'application/json']);
  125. }
  126. public function updateTicketDetails(Request $request)
  127. {
  128. $ticketId = $request->attributes->get('ticketId');
  129. $entityManager = $this->entityManager;
  130. $ticket = $entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->find($ticketId);
  131. if (! $ticket)
  132. $this->noResultFound();
  133. // Proceed only if user has access to the resource
  134. if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
  135. throw new \Exception('Access Denied', 403);
  136. }
  137. $error = false;
  138. $message = '';
  139. if ($request->request->get('subject') == '') {
  140. $error = true;
  141. $message = $this->translator->trans('Error! Subject field is mandatory');
  142. } elseif ($request->request->get('reply') == '') {
  143. $error = true;
  144. $message = $this->translator->trans('Error! Reply field is mandatory');
  145. }
  146. if (! $error) {
  147. $ticket->setSubject($request->request->get('subject'));
  148. $createThread = $this->ticketService->getCreateReply($ticket->getId(), false);
  149. $createThread = $entityManager->getRepository(CoreFrameworkBundleEntities\Thread::class)->find($createThread['id']);
  150. $createThread->setMessage($request->request->get('reply'));
  151. $entityManager->persist($createThread);
  152. $entityManager->persist($ticket);
  153. $entityManager->flush();
  154. $this->addFlash('success', $this->translator->trans('Success ! Ticket has been updated successfully.'));
  155. } else {
  156. $this->addFlash('warning', $message);
  157. }
  158. return $this->redirect($this->generateUrl('helpdesk_member_ticket', ['ticketId' => $ticketId]));
  159. }
  160. public function updateTicketAttributes($ticketId)
  161. {
  162. $entityManager = $this->entityManager;
  163. $request = $this->container->get('request_stack')->getCurrentRequest();
  164. $requestContent = $request->request->all() ?: json_decode($request->getContent(), true);
  165. $ticketId = $ticketId != 0 ? $ticketId : $requestContent['ticketId'];
  166. $ticket = $entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->findOneById($ticketId);
  167. // Proceed only if user has access to the resource
  168. if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
  169. throw new \Exception('Access Denied', 403);
  170. }
  171. // Validate request integrity
  172. if (empty($ticket)) {
  173. $responseContent = [
  174. 'alertClass' => 'danger',
  175. 'alertMessage' => $this->translator->trans('Unable to retrieve details for ticket #%ticketId%.', [
  176. '%ticketId%' => $ticketId,
  177. ]),
  178. ];
  179. return new Response(json_encode($responseContent), 200, ['Content-Type' => 'application/json']);
  180. } else if (!isset($requestContent['attribute'])) {
  181. $responseContent = [
  182. 'alertClass' => 'danger',
  183. 'alertMessage' => $this->translator->trans('Insufficient details provided.'),
  184. ];
  185. return new Response(json_encode($responseContent), 400, ['Content-Type' => 'application/json']);
  186. }
  187. // Update attribute
  188. switch ($requestContent['attribute']) {
  189. case 'agent':
  190. $agent = $entityManager->getRepository(CoreFrameworkBundleEntities\User::class)->findOneById($requestContent['value']);
  191. if (empty($agent)) {
  192. // User does not exist
  193. return new Response(json_encode([
  194. 'alertClass' => 'danger',
  195. 'alertMessage' => $this->translator->trans('Unable to retrieve agent details'),
  196. ]), 404, ['Content-Type' => 'application/json']);
  197. } else {
  198. // Check if an agent instance exists for the user
  199. $agentInstance = $agent->getAgentInstance();
  200. if (empty($agentInstance)) {
  201. // Agent does not exist
  202. return new Response(json_encode([
  203. 'alertClass' => 'danger',
  204. 'alertMessage' => $this->translator->trans('Unable to retrieve agent details'),
  205. ]), 404, ['Content-Type' => 'application/json']);
  206. }
  207. }
  208. $agentDetails = $agentInstance->getPartialDetails();
  209. // Check if ticket is already assigned to the agent
  210. if ($ticket->getAgent() && $agent->getId() === $ticket->getAgent()->getId()) {
  211. return new Response(json_encode([
  212. 'alertClass' => 'success',
  213. 'alertMessage' => $this->translator->trans('Ticket already assigned to %agent%', [
  214. '%agent%' => $agentDetails['name'],
  215. ]),
  216. ]), 200, ['Content-Type' => 'application/json']);
  217. } else {
  218. $ticket->setAgent($agent);
  219. $entityManager->persist($ticket);
  220. $entityManager->flush();
  221. // Trigger Agent Assign event
  222. $event = new CoreWorkflowEvents\Ticket\Agent();
  223. $event
  224. ->setTicket($ticket);
  225. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.workflow.execute');
  226. return new Response(json_encode([
  227. 'alertClass' => 'success',
  228. 'alertMessage' => $this->translator->trans('Ticket successfully assigned to %agent%', [
  229. '%agent%' => $agentDetails['name'],
  230. ]),
  231. ]), 200, ['Content-Type' => 'application/json']);
  232. }
  233. break;
  234. case 'status':
  235. $ticketStatus = $entityManager->getRepository(CoreFrameworkBundleEntities\TicketStatus::class)->findOneById((int) $requestContent['value']);
  236. if (empty($ticketStatus)) {
  237. // Selected ticket status does not exist
  238. return new Response(json_encode([
  239. 'alertClass' => 'danger',
  240. 'alertMessage' => $this->translator->trans('Unable to retrieve status details'),
  241. ]), 404, ['Content-Type' => 'application/json']);
  242. }
  243. if ($ticketStatus->getId() === $ticket->getStatus()->getId()) {
  244. return new Response(json_encode([
  245. 'alertClass' => 'success',
  246. 'alertMessage' => $this->translator->trans('Ticket status already set to %status%', [
  247. '%status%' => $ticketStatus->getDescription()
  248. ]),
  249. ]), 200, ['Content-Type' => 'application/json']);
  250. } else {
  251. $ticket->setStatus($ticketStatus);
  252. $entityManager->persist($ticket);
  253. $entityManager->flush();
  254. // Trigger ticket status event
  255. $event = new CoreWorkflowEvents\Ticket\Status();
  256. $event
  257. ->setTicket($ticket);
  258. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.workflow.execute');
  259. return new Response(json_encode([
  260. 'alertClass' => 'success',
  261. 'alertMessage' => $this->translator->trans('Ticket status update to %status%', [
  262. '%status%' => $ticketStatus->getDescription()
  263. ]),
  264. ]), 200, ['Content-Type' => 'application/json']);
  265. }
  266. break;
  267. case 'priority':
  268. // $this->isAuthorized('ROLE_AGENT_UPDATE_TICKET_PRIORITY');
  269. $ticketPriority = $entityManager->getRepository(CoreFrameworkBundleEntities\TicketPriority::class)->findOneById($requestContent['value']);
  270. if (empty($ticketPriority)) {
  271. // Selected ticket priority does not exist
  272. return new Response(json_encode([
  273. 'alertClass' => 'danger',
  274. 'alertMessage' => $this->translator->trans('Unable to retrieve priority details'),
  275. ]), 404, ['Content-Type' => 'application/json']);
  276. }
  277. if ($ticketPriority->getId() === $ticket->getPriority()->getId()) {
  278. return new Response(json_encode([
  279. 'alertClass' => 'success',
  280. 'alertMessage' => $this->translator->trans('Ticket priority already set to %priority%', [
  281. '%priority%' => $ticketPriority->getDescription()
  282. ]),
  283. ]), 200, ['Content-Type' => 'application/json']);
  284. } else {
  285. $ticket->setPriority($ticketPriority);
  286. $entityManager->persist($ticket);
  287. $entityManager->flush();
  288. // Trigger ticket Priority event
  289. $event = new CoreWorkflowEvents\Ticket\Priority();
  290. $event
  291. ->setTicket($ticket);
  292. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.workflow.execute');
  293. return new Response(json_encode([
  294. 'alertClass' => 'success',
  295. 'alertMessage' => $this->translator->trans('Ticket priority updated to %priority%', [
  296. '%priority%' => $ticketPriority->getDescription()
  297. ]),
  298. ]), 200, ['Content-Type' => 'application/json']);
  299. }
  300. break;
  301. case 'group':
  302. $supportGroup = $entityManager->getRepository(CoreFrameworkBundleEntities\SupportGroup::class)->findOneById($requestContent['value']);
  303. if (empty($supportGroup)) {
  304. if ($requestContent['value'] == "") {
  305. if ($ticket->getSupportGroup() != null) {
  306. $ticket->setSupportGroup(null);
  307. $entityManager->persist($ticket);
  308. $entityManager->flush();
  309. }
  310. $responseCode = 200;
  311. $response = [
  312. 'alertClass' => 'success',
  313. 'alertMessage' => $this->translator->trans('Ticket support group updated successfully'),
  314. ];
  315. } else {
  316. $responseCode = 404;
  317. $response = [
  318. 'alertClass' => 'danger',
  319. 'alertMessage' => $this->translator->trans('Unable to retrieve support group details'),
  320. ];
  321. }
  322. return new Response(json_encode($response), $responseCode, ['Content-Type' => 'application/json']);;
  323. }
  324. if ($ticket->getSupportGroup() != null && $supportGroup->getId() === $ticket->getSupportGroup()->getId()) {
  325. return new Response(json_encode([
  326. 'alertClass' => 'success',
  327. 'alertMessage' => 'Ticket already assigned to support group ' . $supportGroup->getName(),
  328. ]), 200, ['Content-Type' => 'application/json']);
  329. } else {
  330. $ticket->setSupportGroup($supportGroup);
  331. $entityManager->persist($ticket);
  332. $entityManager->flush();
  333. // Trigger Support group event
  334. $event = new CoreWorkflowEvents\Ticket\Group();
  335. $event
  336. ->setTicket($ticket);
  337. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.workflow.execute');
  338. return new Response(json_encode([
  339. 'alertClass' => 'success',
  340. 'alertMessage' => $this->translator->trans('Ticket assigned to support group ') . $supportGroup->getName(),
  341. ]), 200, ['Content-Type' => 'application/json']);
  342. }
  343. break;
  344. case 'team':
  345. $supportTeam = $entityManager->getRepository(CoreFrameworkBundleEntities\SupportTeam::class)->findOneById($requestContent['value']);
  346. if (empty($supportTeam)) {
  347. if ($requestContent['value'] == "") {
  348. if ($ticket->getSupportTeam() != null) {
  349. $ticket->setSupportTeam(null);
  350. $entityManager->persist($ticket);
  351. $entityManager->flush();
  352. }
  353. $responseCode = 200;
  354. $response = [
  355. 'alertClass' => 'success',
  356. 'alertMessage' => $this->translator->trans('Ticket support team updated successfully'),
  357. ];
  358. } else {
  359. $responseCode = 404;
  360. $response = [
  361. 'alertClass' => 'danger',
  362. 'alertMessage' => $this->translator->trans('Unable to retrieve support team details'),
  363. ];
  364. }
  365. return new Response(json_encode($response), $responseCode, ['Content-Type' => 'application/json']);;
  366. }
  367. if ($ticket->getSupportTeam() != null && $supportTeam->getId() === $ticket->getSupportTeam()->getId()) {
  368. return new Response(json_encode([
  369. 'alertClass' => 'success',
  370. 'alertMessage' => 'Ticket already assigned to support team ' . $supportTeam->getName(),
  371. ]), 200, ['Content-Type' => 'application/json']);
  372. } else {
  373. $ticket->setSupportTeam($supportTeam);
  374. $entityManager->persist($ticket);
  375. $entityManager->flush();
  376. // Trigger ticket delete event
  377. $event = new CoreWorkflowEvents\Ticket\Team();
  378. $event
  379. ->setTicket($ticket);
  380. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.workflow.execute');
  381. return new Response(json_encode([
  382. 'alertClass' => 'success',
  383. 'alertMessage' => 'Ticket assigned to support team ' . $supportTeam->getName(),
  384. ]), 200, ['Content-Type' => 'application/json']);
  385. }
  386. break;
  387. case 'type':
  388. // $this->isAuthorized('ROLE_AGENT_UPDATE_TICKET_TYPE');
  389. $ticketType = $entityManager->getRepository(CoreFrameworkBundleEntities\TicketType::class)->findOneById($requestContent['value']);
  390. if (empty($ticketType)) {
  391. // Selected ticket priority does not exist
  392. return new Response(json_encode([
  393. 'alertClass' => 'danger',
  394. 'alertMessage' => 'Unable to retrieve ticket type details',
  395. ]), 404, ['Content-Type' => 'application/json']);
  396. }
  397. if (null != $ticket->getType() && $ticketType->getId() === $ticket->getType()->getId()) {
  398. return new Response(json_encode([
  399. 'alertClass' => 'success',
  400. 'alertMessage' => 'Ticket type already set to ' . $ticketType->getCode(),
  401. ]), 200, ['Content-Type' => 'application/json']);
  402. } else {
  403. $ticket->setType($ticketType);
  404. $entityManager->persist($ticket);
  405. $entityManager->flush();
  406. // Trigger ticket delete event
  407. $event = new CoreWorkflowEvents\Ticket\Type();
  408. $event
  409. ->setTicket($ticket);
  410. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.workflow.execute');
  411. return new Response(json_encode([
  412. 'alertClass' => 'success',
  413. 'alertMessage' => 'Ticket type updated to ' . $ticketType->getDescription(),
  414. ]), 200, ['Content-Type' => 'application/json']);
  415. }
  416. break;
  417. case 'label':
  418. $label = $entityManager->getRepository(CoreFrameworkBundleEntities\SupportLabel::class)->find($requestContent['labelId']);
  419. if ($label) {
  420. $ticket->removeSupportLabel($label);
  421. $entityManager->persist($ticket);
  422. $entityManager->flush();
  423. return new Response(json_encode([
  424. 'alertClass' => 'success',
  425. 'alertMessage' => $this->translator->trans('Success ! Ticket to label removed successfully.'),
  426. ]), 200, ['Content-Type' => 'application/json']);
  427. }
  428. break;
  429. case 'country':
  430. if (
  431. ! $ticket->getCountry()
  432. || $ticket->getCountry() != $requestContent['value']
  433. ) {
  434. $customer = $ticket->getCustomer();
  435. $customerTickets = $entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->findBy([
  436. 'customer' => $customer->getId(),
  437. ]);
  438. foreach ($customerTickets as $customerTicket) {
  439. $customerTicket
  440. ->setCountry($requestContent['value'] ?? NULL);
  441. $entityManager->persist($customerTicket);
  442. }
  443. $entityManager->flush();
  444. return new Response(json_encode([
  445. 'alertClass' => 'success',
  446. 'alertMessage' => $this->translator->trans('Success ! Ticket country updated successfully.'),
  447. ]), 200, ['Content-Type' => 'application/json']);
  448. } else {
  449. return new Response(json_encode([
  450. 'alertClass' => 'success',
  451. 'alertMessage' => $this->translator->trans('No changes detected in the provided ticket country details.'),
  452. ]), 200, ['Content-Type' => 'application/json']);
  453. }
  454. default:
  455. break;
  456. }
  457. return new Response(json_encode([]), 400, ['Content-Type' => 'application/json']);
  458. }
  459. public function listTicketCollectionXHR(Request $request)
  460. {
  461. if ($request->isXmlHttpRequest()) {
  462. $paginationResponse = $this->ticketService->paginateMembersTicketCollection($request);
  463. return new Response(json_encode($paginationResponse), 200, ['Content-Type' => 'application/json']);
  464. }
  465. return new Response(json_encode([]), 404, ['Content-Type' => 'application/json']);
  466. }
  467. public function updateTicketCollectionXHR(Request $request)
  468. {
  469. if ($request->isXmlHttpRequest()) {
  470. $massResponse = $this->ticketService->massXhrUpdate($request);
  471. return new Response(json_encode($massResponse), 200, ['Content-Type' => 'application/json']);
  472. }
  473. return new Response(json_encode([]), 404);
  474. }
  475. public function loadTicketFilterOptionsXHR(Request $request)
  476. {
  477. $json = [];
  478. if ($request->isXmlHttpRequest()) {
  479. $requiredOptions = $request->request->all();
  480. foreach ($requiredOptions as $filterType => $values) {
  481. $json[$filterType] = $this->ticketService->getDemanedFilterOptions($filterType, $values);
  482. }
  483. }
  484. $response = new Response(json_encode($json));
  485. $response->headers->set('Content-Type', 'application/json');
  486. return $response;
  487. }
  488. public function saveTicketLabel(Request $request)
  489. {
  490. $entityManager = $this->entityManager;
  491. $request = $this->container->get('request_stack')->getCurrentRequest();
  492. $requestContent = json_decode($request->getContent(), true);
  493. $ticket = $entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->findOneById($requestContent['ticketId']);
  494. // Process only if user have ticket access
  495. if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
  496. throw new \Exception('Access Denied', 403);
  497. }
  498. if ('POST' == $request->getMethod()) {
  499. $responseContent = [];
  500. $user = $this->userService->getSessionUser();
  501. $supportLabel = $entityManager->getRepository(CoreFrameworkBundleEntities\SupportLabel::class)->findOneBy([
  502. 'user' => $user->getId(),
  503. 'name' => $requestContent['name'],
  504. ]);
  505. if (empty($supportLabel)) {
  506. $supportLabel = new CoreFrameworkBundleEntities\SupportLabel();
  507. $supportLabel->setName($requestContent['name']);
  508. $supportLabel->setUser($user);
  509. $entityManager->persist($supportLabel);
  510. $entityManager->flush();
  511. }
  512. $ticketLabelCollection = $ticket->getSupportLabels()->toArray();
  513. if (empty($ticketLabelCollection)) {
  514. $ticket->addSupportLabel($supportLabel);
  515. $entityManager->persist($ticket);
  516. $entityManager->flush();
  517. $responseContent['alertClass'] = 'success';
  518. $responseContent['alertMessage'] = $this->translator->trans(
  519. 'Label %label% added to ticket successfully',
  520. [
  521. '%label%' => $supportLabel->getName(),
  522. ]
  523. );
  524. } else {
  525. $isLabelAlreadyAdded = false;
  526. foreach ($ticketLabelCollection as $ticketLabel) {
  527. if ($supportLabel->getId() == $ticketLabel->getId()) {
  528. $isLabelAlreadyAdded = true;
  529. break;
  530. }
  531. }
  532. if (false == $isLabelAlreadyAdded) {
  533. $ticket->addSupportLabel($supportLabel);
  534. $entityManager->persist($ticket);
  535. $entityManager->flush();
  536. $responseContent['alertClass'] = 'success';
  537. $responseContent['alertMessage'] = $this->translator->trans(
  538. 'Label %label% added to ticket successfully',
  539. [
  540. '%label%' => $supportLabel->getName(),
  541. ]
  542. );
  543. } else {
  544. $responseContent['alertClass'] = 'warning';
  545. $responseContent['alertMessage'] = $this->translator->trans(
  546. 'Label %label% already added to ticket',
  547. [
  548. '%label%' => $supportLabel->getName(),
  549. ]
  550. );
  551. }
  552. }
  553. $responseContent['label'] = [
  554. 'id' => $supportLabel->getId(),
  555. 'name' => $supportLabel->getName(),
  556. 'color' => $supportLabel->getColorCode(),
  557. ];
  558. return new Response(json_encode($responseContent), 200, ['Content-Type' => 'application/json']);
  559. }
  560. return new Response(json_encode([]), 404, ['Content-Type' => 'application/json']);
  561. }
  562. public function loadTicketSearchFilterOptions(Request $request)
  563. {
  564. if (true === $request->isXmlHttpRequest()) {
  565. switch ($request->query->get('type')) {
  566. case 'agent':
  567. $filtersResponse = $this->userService->getAgentPartialDataCollection($request);
  568. break;
  569. case 'customer':
  570. $filtersResponse = $this->userService->getCustomersPartial($request);
  571. break;
  572. case 'group':
  573. $filtersResponse = $this->userService->getSupportGroups($request);
  574. break;
  575. case 'team':
  576. $filtersResponse = $this->userService->getSupportTeams($request);
  577. break;
  578. case 'tag':
  579. $filtersResponse = $this->ticketService->getTicketTags($request);
  580. break;
  581. case 'label':
  582. $searchTerm = $request->query->get('query');
  583. $entityManager = $this->getDoctrine()->getManager();
  584. $supportLabelQuery = $entityManager->createQueryBuilder()->select('supportLabel')
  585. ->from(CoreFrameworkBundleEntities\SupportLabel::class, 'supportLabel')
  586. ->where('supportLabel.user = :user')->setParameter('user', $this->userService->getSessionUser());
  587. if (!empty($searchTerm)) {
  588. $supportLabelQuery->andWhere('supportLabel.name LIKE :labelName')->setParameter('labelName', '%' . urldecode($searchTerm) . '%');
  589. }
  590. $supportLabelCollection = $supportLabelQuery->getQuery()->getArrayResult();
  591. return new Response(json_encode($supportLabelCollection), 200, ['Content-Type' => 'application/json']);
  592. break;
  593. default:
  594. break;
  595. }
  596. }
  597. return new Response(json_encode([]), 404, ['Content-Type' => 'application/json']);
  598. }
  599. public function loadTicketCollectionSearchFilterOptionsXHR(Request $request)
  600. {
  601. $json = [];
  602. if ($request->isXmlHttpRequest()) {
  603. if ($request->query->get('type') == 'agent') {
  604. $json = $this->userService->getAgentsPartialDetails($request);
  605. } elseif ($request->query->get('type') == 'customer') {
  606. $json = $this->userService->getCustomersPartial($request);
  607. } elseif ($request->query->get('type') == 'group') {
  608. $json = $this->userService->getSupportGroups($request);
  609. } elseif ($request->query->get('type') == 'team') {
  610. $json = $this->userService->getSupportTeams($request);
  611. } elseif ($request->query->get('type') == 'tag') {
  612. $json = $this->ticketService->getTicketTags($request);
  613. } elseif ($request->query->get('type') == 'label') {
  614. $json = $this->ticketService->getLabels($request);
  615. }
  616. }
  617. return new Response(json_encode($json), 200, ['Content-Type' => 'application/json']);
  618. }
  619. public function listTicketTypeCollectionXHR(Request $request)
  620. {
  621. if (! $this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  622. return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  623. }
  624. if (true === $request->isXmlHttpRequest()) {
  625. $paginationResponse = $this->ticketService->paginateMembersTicketTypeCollection($request);
  626. return new Response(json_encode($paginationResponse), 200, ['Content-Type' => 'application/json']);
  627. }
  628. return new Response(json_encode([]), 404, ['Content-Type' => 'application/json']);
  629. }
  630. public function removeTicketTypeXHR($typeId, Request $request)
  631. {
  632. if (! $this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  633. return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  634. }
  635. $json = [];
  636. if ($request->getMethod() == "DELETE") {
  637. $em = $this->entityManager;
  638. $id = $request->attributes->get('typeId');
  639. $type = $em->getRepository(CoreFrameworkBundleEntities\TicketType::class)->find($id);
  640. $em->remove($type);
  641. $em->flush();
  642. $json['alertClass'] = 'success';
  643. $json['alertMessage'] = $this->translator->trans('Success ! Type removed successfully.');
  644. }
  645. $response = new Response(json_encode($json));
  646. $response->headers->set('Content-Type', 'application/json');
  647. return $response;
  648. }
  649. public function listTagCollectionXHR(Request $request)
  650. {
  651. if (! $this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TAG')) {
  652. return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  653. }
  654. if (true === $request->isXmlHttpRequest()) {
  655. $paginationResponse = $this->ticketService->paginateMembersTagCollection($request);
  656. return new Response(json_encode($paginationResponse), 200, ['Content-Type' => 'application/json']);
  657. }
  658. return new Response(json_encode([]), 404, ['Content-Type' => 'application/json']);
  659. }
  660. public function applyTicketPreparedResponseXHR(Request $request)
  661. {
  662. $id = $request->attributes->get('id');
  663. $ticketId = $request->attributes->get('ticketId');
  664. $ticket = $this->entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->findOneById($ticketId);
  665. // Process only if user have ticket access
  666. if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
  667. return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  668. }
  669. $event = new GenericEvent($id, [
  670. 'entity' => $ticket
  671. ]);
  672. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.prepared_response.execute');
  673. $this->addFlash('success', $this->translator->trans('Success ! Prepared Response applied successfully.'));
  674. return $this->redirect($this->generateUrl('helpdesk_member_ticket', ['ticketId' => $ticketId]));
  675. }
  676. public function loadTicketSavedReplies(Request $request)
  677. {
  678. $json = array();
  679. $data = $request->query->all();
  680. if ($request->isXmlHttpRequest()) {
  681. try {
  682. $json['message'] = $this->ticketService->getSavedReplyContent($data['id'], $data['ticketId']);
  683. } catch (\Exception $e) {
  684. $json['alertClass'] = 'danger';
  685. $json['alertMessage'] = $e->getMessage();
  686. return new Response(json_encode($json), 400, ['Content-Type' => 'application/json']);
  687. }
  688. }
  689. $response = new Response(json_encode($json));
  690. return $response;
  691. }
  692. public function createTicketTagXHR(Request $request)
  693. {
  694. $json = [];
  695. $content = json_decode($request->getContent(), true);
  696. $em = $this->entityManager;
  697. $ticket = $em->getRepository(CoreFrameworkBundleEntities\Ticket::class)->find($content['ticketId']);
  698. // Process only if user have ticket access
  699. if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
  700. throw new \Exception('Access Denied', 403);
  701. }
  702. if ($request->getMethod() == "POST") {
  703. $tag = new CoreFrameworkBundleEntities\Tag();
  704. if ($content['name'] != "") {
  705. $checkTag = $em->getRepository(CoreFrameworkBundleEntities\Tag::class)->findOneBy(array('name' => $content['name']));
  706. if (! $checkTag) {
  707. $tag->setName($content['name']);
  708. $em->persist($tag);
  709. $em->flush();
  710. //$json['tag'] = json_decode($this->objectSerializer($tag));
  711. $ticket->addSupportTag($tag);
  712. } else {
  713. //$json['tag'] = json_decode($this->objectSerializer($checkTag));
  714. $ticket->addSupportTag($checkTag);
  715. }
  716. $em->persist($ticket);
  717. $em->flush();
  718. $json['alertClass'] = 'success';
  719. $json['alertMessage'] = $this->translator->trans('Success ! Tag added successfully.');
  720. } else {
  721. $json['alertClass'] = 'danger';
  722. $json['alertMessage'] = $this->translator->trans('Please enter tag name.');
  723. }
  724. } elseif ($request->getMethod() == "DELETE") {
  725. $tag = $em->getRepository(CoreFrameworkBundleEntities\Tag::class)->findOneBy(array('id' => $request->attributes->get('id')));
  726. if ($tag) {
  727. $articles = $em->getRepository(ArticleTags::class)->findOneBy(array('tagId' => $tag->getId()));
  728. if ($articles)
  729. foreach ($articles as $entry) {
  730. $em->remove($entry);
  731. }
  732. $ticket->removeSupportTag($tag);
  733. $em->persist($ticket);
  734. $em->flush();
  735. $json['alertClass'] = 'success';
  736. $json['alertMessage'] = $this->translator->trans('Success ! Tag unassigned successfully.');
  737. } else {
  738. $json['alertClass'] = 'danger';
  739. $json['alertMessage'] = $this->translator->trans('Error ! Invalid tag.');
  740. }
  741. }
  742. $response = new Response(json_encode($json));
  743. $response->headers->set('Content-Type', 'application/json');
  744. return $response;
  745. }
  746. public function getSearchFilterOptionsXhr(Request $request)
  747. {
  748. $json = [];
  749. if ($request->isXmlHttpRequest()) {
  750. if ($request->query->get('type') == 'agent') {
  751. $json = $this->userService->getAgentsPartialDetails($request);
  752. } elseif ($request->query->get('type') == 'customer') {
  753. $json = $this->userService->getCustomersPartial($request);
  754. } elseif ($request->query->get('type') == 'group') {
  755. $json = $this->userService->getSupportGroups($request);
  756. } elseif ($request->query->get('type') == 'team') {
  757. $json = $this->userService->getSupportTeams($request);
  758. } elseif ($request->query->get('type') == 'tag') {
  759. $json = $this->ticketService->getTicketTags($request);
  760. } elseif ($request->query->get('type') == 'label') {
  761. $json = $this->ticketService->getLabels($request);
  762. }
  763. }
  764. $response = new Response(json_encode($json));
  765. $response->headers->set('Content-Type', 'application/json');
  766. return $response;
  767. }
  768. public function updateCollaboratorXHR(Request $request)
  769. {
  770. $json = [];
  771. $content = json_decode($request->getContent(), true);
  772. $em = $this->entityManager;
  773. $ticket = $em->getRepository(CoreFrameworkBundleEntities\Ticket::class)->find($content['ticketId']);
  774. // Process only if user have ticket access
  775. if (false == $this->ticketService->isTicketAccessGranted($ticket)) {
  776. throw new \Exception('Access Denied', 403);
  777. }
  778. if ($request->getMethod() == "POST") {
  779. if ($content['email'] == $ticket->getCustomer()->getEmail()) {
  780. $json['alertClass'] = 'danger';
  781. $json['alertMessage'] = $this->translator->trans('Error ! Customer can not be added as collaborator.');
  782. } else {
  783. $data = array(
  784. 'from' => $content['email'],
  785. 'firstName' => ($firstName = ucfirst(current(explode('@', $content['email'])))),
  786. 'lastName' => ' ',
  787. 'role' => 4,
  788. );
  789. $supportRole = $em->getRepository(CoreFrameworkBundleEntities\SupportRole::class)->findOneByCode('ROLE_CUSTOMER');
  790. $collaborator = $this->userService->createUserInstance($data['from'], $data['firstName'], $supportRole, $extras = ["active" => true]);
  791. $checkTicket = $em->getRepository(CoreFrameworkBundleEntities\Ticket::class)->isTicketCollaborator($ticket, $content['email']);
  792. if (! $checkTicket) {
  793. $ticket->addCollaborator($collaborator);
  794. $em->persist($ticket);
  795. $em->flush();
  796. $ticket->lastCollaborator = $collaborator;
  797. if ($collaborator->getCustomerInstance()) {
  798. $json['collaborator'] = $collaborator->getCustomerInstance()->getPartialDetails();
  799. } else {
  800. $json['collaborator'] = $collaborator->getAgentInstance()->getPartialDetails();
  801. }
  802. $event = new CoreWorkflowEvents\Ticket\Collaborator();
  803. $event
  804. ->setTicket($ticket);
  805. $this->eventDispatcher->dispatch($event, 'uvdesk.automation.workflow.execute');
  806. $json['alertClass'] = 'success';
  807. $json['alertMessage'] = $this->translator->trans('Success ! Collaborator added successfully.');
  808. } else {
  809. $json['alertClass'] = 'danger';
  810. $message = "Collaborator is already added.";
  811. $json['alertMessage'] = $this->translator->trans('Error ! ' . $message);
  812. }
  813. }
  814. } elseif ($request->getMethod() == "DELETE") {
  815. $collaborator = $em->getRepository(CoreFrameworkBundleEntities\User::class)->findOneBy(array('id' => $request->attributes->get('id')));
  816. if ($collaborator) {
  817. $ticket->removeCollaborator($collaborator);
  818. $em->persist($ticket);
  819. $em->flush();
  820. $json['alertClass'] = 'success';
  821. $json['alertMessage'] = $this->translator->trans('Success ! Collaborator removed successfully.');
  822. } else {
  823. $json['alertClass'] = 'danger';
  824. $json['alertMessage'] = $this->translator->trans('Error ! Invalid Collaborator.');
  825. }
  826. }
  827. $response = new Response(json_encode($json));
  828. $response->headers->set('Content-Type', 'application/json');
  829. return $response;
  830. }
  831. // Apply quick Response action
  832. public function getTicketQuickViewDetailsXhr(Request $request, ContainerInterface $container)
  833. {
  834. $json = [];
  835. if ($request->isXmlHttpRequest()) {
  836. $ticketId = $request->query->get('ticketId');
  837. $json = $this->entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->getTicketDetails($request->query, $container);
  838. }
  839. $response = new Response(json_encode($json));
  840. $response->headers->set('Content-Type', 'application/json');
  841. return $response;
  842. }
  843. public function updateTicketTagXHR(Request $request, $tagId)
  844. {
  845. $content = json_decode($request->getContent(), true);
  846. $entityManager = $this->entityManager;
  847. if (isset($content['name']) && $content['name'] != "") {
  848. $checkTag = $entityManager->getRepository(CoreFrameworkBundleEntities\Tag::class)->findOneBy(array('id' => $tagId));
  849. if ($checkTag) {
  850. $checkTag->setName($content['name']);
  851. $entityManager->persist($checkTag);
  852. $entityManager->flush();
  853. }
  854. $json['alertClass'] = 'success';
  855. $json['alertMessage'] = $this->translator->trans('Success ! Tag updated successfully.');
  856. }
  857. $response = new Response(json_encode($json));
  858. $response->headers->set('Content-Type', 'application/json');
  859. return $response;
  860. }
  861. public function removeTicketTagXHR($tagId)
  862. {
  863. $entityManager = $this->entityManager;
  864. $checkTag = $entityManager->getRepository(CoreFrameworkBundleEntities\Tag::class)->findOneBy(array('id' => $tagId));
  865. if ($checkTag) {
  866. $entityManager->remove($checkTag);
  867. $entityManager->flush();
  868. $json['alertClass'] = 'success';
  869. $json['alertMessage'] = $this->translator->trans('Success ! Tag removed successfully.');
  870. }
  871. $response = new Response(json_encode($json));
  872. $response->headers->set('Content-Type', 'application/json');
  873. return $response;
  874. }
  875. // Agent Access Quick view check.
  876. public function getAgentAcessQuickViewDetailsXhr(Request $request)
  877. {
  878. $agentAccessData = [];
  879. $ticketId = $request->query->get('ticketId');
  880. $entityManager = $this->entityManager;
  881. $supportGroupRepository = $entityManager->getRepository(CoreFrameworkBundleEntities\SupportGroup::class);
  882. $supportTeamRepository = $entityManager->getRepository(CoreFrameworkBundleEntities\SupportTeam::class);
  883. $supportPrivilegeRepository = $entityManager->getRepository(CoreFrameworkBundleEntities\SupportPrivilege::class);
  884. $ticket = $entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->findOneById($ticketId);
  885. $userInstance = $entityManager->getRepository(CoreFrameworkBundleEntities\UserInstance::class)->findOneBy([
  886. 'user' => $ticket->getAgent()->getId(),
  887. 'supportRole' => 3,
  888. ]);
  889. if ($userInstance) {
  890. $assignedUserPrivilegeIds = (is_object($userInstance->getSupportPrivileges()) && method_exists($userInstance->getSupportPrivileges(), 'toArray'))
  891. ? $userInstance->getSupportPrivileges()->toArray()
  892. : [];
  893. $assignedUserGroupReferenceIds = (is_object($userInstance->getSupportGroups()) && method_exists($userInstance->getSupportGroups(), 'toArray'))
  894. ? $userInstance->getSupportGroups()->toArray()
  895. : [];
  896. $assignedUserTeamReferenceIds = (is_object($userInstance->getSupportTeams()) && method_exists($userInstance->getSupportTeams(), 'toArray'))
  897. ? $userInstance->getSupportTeams()->toArray()
  898. : [];
  899. if ($assignedUserGroupReferenceIds) {
  900. foreach ($assignedUserGroupReferenceIds as $groupId) {
  901. $agentAccessData['agentGroups'][] = $supportGroupRepository->findOneBy(['id' => $groupId])->getName();
  902. }
  903. }
  904. if ($assignedUserTeamReferenceIds) {
  905. foreach ($assignedUserTeamReferenceIds as $teamId) {
  906. $agentAccessData['agentTeam'][] = $supportTeamRepository->findOneBy(['id' => $teamId])->getName();
  907. }
  908. }
  909. if ($assignedUserPrivilegeIds) {
  910. foreach ($assignedUserPrivilegeIds as $previlegeId) {
  911. $agentAccessData['agentPrivileges'][] = $supportPrivilegeRepository->findOneBy(['id' => $previlegeId])->getName();
  912. }
  913. }
  914. $agentAccessData['ticketView'] = self::TICKET_ACCESS_LEVEL[$userInstance->getTicketAccessLevel()];
  915. }
  916. $response = new Response(json_encode($agentAccessData));
  917. $response->headers->set('Content-Type', 'application/json');
  918. return $response;
  919. }
  920. // Public Link URL For Ticket
  921. public function generateCustomerPublicTicketResourceAccessLink($id, Request $request, ContainerInterface $container)
  922. {
  923. $entityManager = $this->entityManager;
  924. $accessRule = $this->entityManager->getRepository(KnowledgebaseWebsite::class)->findOneById(1);
  925. if (
  926. empty($accessRule)
  927. || $accessRule->getPublicResourceAccessAttemptLimit() == null
  928. || $accessRule->getPublicResourceAccessAttemptLimit() == 0
  929. ) {
  930. return new JsonResponse([
  931. 'status' => false,
  932. 'message' => "No public URL access limit is currently set for tickets.",
  933. ]);
  934. }
  935. $ticket = $entityManager->getRepository(CoreFrameworkBundleEntities\Ticket::class)->findOneBy([
  936. 'id' => $id
  937. ]);
  938. $originatingUrl = $request->headers->get('referer');
  939. $expectedUrl = $this->generateUrl('helpdesk_member_ticket', ['ticketId' => $ticket->getId()], UrlGeneratorInterface::ABSOLUTE_URL);
  940. if (empty($originatingUrl) || $originatingUrl != $expectedUrl) {
  941. return new JsonResponse([
  942. 'status' => false,
  943. 'message' => "Invalid request. Please try again later.",
  944. ], 404);
  945. }
  946. if (empty($ticket)) {
  947. return new JsonResponse([
  948. 'status' => false,
  949. 'message' => "No tickets were found for the provided details.",
  950. ], 404);
  951. }
  952. $resourceUrl = $container->get('ticket.service')->generateTicketCustomerReadOnlyResourceAccessLink($ticket);
  953. return new JsonResponse([
  954. 'status' => true,
  955. 'message' => "Public resource access link generated successfully!",
  956. 'resourceUrl' => $resourceUrl,
  957. ]);
  958. }
  959. }