vendor/uvdesk/api-bundle/API/Tickets.php line 36

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\ApiBundle\API;
  3. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  4. use Symfony\Component\HttpFoundation\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. use Symfony\Component\HttpFoundation\JsonResponse;
  7. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  8. use Symfony\Component\EventDispatcher\GenericEvent;
  9. use Symfony\Component\Serializer\Serializer;
  10. use Symfony\Component\Serializer\Encoder\XmlEncoder;
  11. use Symfony\Component\Serializer\Encoder\JsonEncoder;
  12. use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
  13. use Symfony\Component\DependencyInjection\ContainerInterface;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Attachment;
  15. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportGroup;
  16. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportLabel;
  17. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportRole;
  18. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportTeam;
  19. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket;
  20. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketPriority;
  21. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketStatus;
  22. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketType;
  23. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  24. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  25. use Webkul\UVDesk\CoreFrameworkBundle\Services\UVDeskService;
  26. class Tickets extends AbstractController
  27. {
  28. /**
  29. * Return support tickets.
  30. *
  31. * @param Request $request
  32. */
  33. public function fetchTickets(Request $request, ContainerInterface $container, UVDeskService $uvdesk)
  34. {
  35. $json = [];
  36. $entityManager = $this->getDoctrine()->getManager();
  37. $ticketRepository = $this->getDoctrine()->getRepository(Ticket::class);
  38. $userRepository = $this->getDoctrine()->getRepository(User::class);
  39. if ($request->query->get('actAsType')) {
  40. switch ($request->query->get('actAsType')) {
  41. case 'customer':
  42. $email = $request->query->get('actAsEmail');
  43. $customer = $entityManager->getRepository(User::class)->findOneByEmail($email);
  44. if ($customer) {
  45. $json = $ticketRepository->getAllCustomerTickets($request->query, $container, $customer);
  46. } else {
  47. $json['error'] = $container->get('translator')->trans('Error! Resource not found.');
  48. return new JsonResponse($json, Response::HTTP_NOT_FOUND);
  49. }
  50. return new JsonResponse($json);
  51. case 'agent':
  52. $email = $request->query->get('actAsEmail');
  53. $user = $entityManager->getRepository(User::class)->findOneByEmail($email);
  54. if ($user) {
  55. $request->query->set('agent', $user->getId());
  56. } else {
  57. $json['error'] = $container->get('translator')->trans('Error! Resource not found.');
  58. return new JsonResponse($json, Response::HTTP_NOT_FOUND);
  59. }
  60. break;
  61. default:
  62. $json['error'] = $container->get('translator')->trans('Error! invalid actAs details.');
  63. return new JsonResponse($json, Response::HTTP_BAD_REQUEST);
  64. }
  65. }
  66. $json = $ticketRepository->getAllTickets($request->query, $container);
  67. $collection = $json['tickets'];
  68. $pagination = $json['pagination'];
  69. // Resolve asset paths
  70. $defaultAgentProfileImagePath = $this->getParameter('assets_default_agent_profile_image_path');
  71. $defaultCustomerProfileImagePath = $this->getParameter('assets_default_customer_profile_image_path');
  72. $user = $this->getUser();
  73. $userInstance = $user->getCurrentInstance();
  74. $currentUserDetails = [
  75. 'id' => $user->getId(),
  76. 'email' => $user->getEmail(),
  77. 'name' => $user->getFirstName() . ' ' . $user->getLastname(),
  78. 'profileImagePath' => $uvdesk->generateCompleteLocalResourcePathUri($userInstance->getProfileImagePath() ?? $defaultAgentProfileImagePath)
  79. ];
  80. foreach ($collection as $index => $ticket) {
  81. // Resolve assets: Assigned agent
  82. if (!empty($ticket['agent'])) {
  83. $profileImagePath = $uvdesk->generateCompleteLocalResourcePathUri($ticket['agent']['profileImagePath'] ?? $defaultAgentProfileImagePath);
  84. $smallThumbnailPath = $uvdesk->generateCompleteLocalResourcePathUri($ticket['agent']['smallThumbnail'] ?? $defaultAgentProfileImagePath);
  85. $collection[$index]['agent']['profileImagePath'] = $profileImagePath;
  86. $collection[$index]['agent']['smallThumbnail'] = $smallThumbnailPath;
  87. }
  88. // Resolve assets: Customer
  89. if (!empty($ticket['customer'])) {
  90. $profileImagePath = $uvdesk->generateCompleteLocalResourcePathUri($ticket['customer']['profileImagePath'] ?? $defaultCustomerProfileImagePath);
  91. $smallThumbnailPath = $uvdesk->generateCompleteLocalResourcePathUri($ticket['customer']['smallThumbnail'] ?? $defaultCustomerProfileImagePath);
  92. $collection[$index]['customer']['profileImagePath'] = $profileImagePath;
  93. $collection[$index]['customer']['smallThumbnail'] = $smallThumbnailPath;
  94. }
  95. }
  96. // Available helpdesk agents collection
  97. $agents = $container->get('user.service')->getAgentsPartialDetails();
  98. return new JsonResponse([
  99. 'tickets' => $collection,
  100. 'pagination' => $pagination,
  101. 'userDetails' => $currentUserDetails,
  102. 'agents' => $agents,
  103. 'status' => $container->get('ticket.service')->getStatus(),
  104. 'group' => $userRepository->getSupportGroups(),
  105. 'team' => $userRepository->getSupportTeams(),
  106. 'priority' => $container->get('ticket.service')->getPriorities(),
  107. 'type' => $container->get('ticket.service')->getTypes(),
  108. 'source' => $container->get('ticket.service')->getAllSources(),
  109. ]);
  110. return new JsonResponse($json);
  111. }
  112. /**
  113. * Return support tickets metadata.
  114. *
  115. * @param Request $request
  116. */
  117. public function fetchTicketsMetadata(Request $request)
  118. {
  119. return new JsonResponse([]);
  120. }
  121. /**
  122. * Trash support tickets.
  123. *
  124. * @param Request $request
  125. * @return void
  126. */
  127. public function trashTicket(Request $request, ContainerInterface $container)
  128. {
  129. $ticketId = $request->attributes->get('ticketId');
  130. $entityManager = $this->getDoctrine()->getManager();
  131. $ticket = $entityManager->getRepository(Ticket::class)->find($ticketId);
  132. if (!$ticket) {
  133. throw new NotFoundHttpException('Page Not Found');
  134. }
  135. if (!$ticket->getIsTrashed()) {
  136. $ticket->setIsTrashed(1);
  137. $entityManager->persist($ticket);
  138. $entityManager->flush();
  139. $json['success'] = $container->get('translator')->trans('Success ! Ticket moved to trash successfully.');
  140. $statusCode = Response::HTTP_OK;
  141. // Trigger ticket delete event
  142. $event = new CoreWorkflowEvents\Ticket\Delete();
  143. $event
  144. ->setTicket($ticket)
  145. ;
  146. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  147. } else {
  148. $json['error'] = $container->get('translator')->trans('Warning ! Ticket is already in trash.');
  149. $statusCode = Response::HTTP_BAD_REQUEST;
  150. }
  151. return new JsonResponse($json, $statusCode);
  152. }
  153. /**
  154. * Create support tickets.
  155. *
  156. * @param Request $request
  157. * @return void
  158. */
  159. public function createTicket(Request $request, ContainerInterface $container)
  160. {
  161. $data = $request->request->all()? : json_decode($request->getContent(),true);
  162. foreach ($data as $key => $value) {
  163. if (!in_array($key, ['subject', 'group', 'type', 'status','locale','domain', 'priority', 'agent', 'replies', 'createdAt', 'updatedAt', 'customFields', 'files', 'from', 'name', 'message', 'tags', 'actAsType', 'actAsEmail'])) {
  164. unset($data[$key]);
  165. }
  166. }
  167. if (
  168. !(isset($data['from'])
  169. && isset($data['name'])
  170. && isset($data['subject'])
  171. && isset($data['message'])
  172. && isset($data['actAsType'])
  173. || isset($data['actAsEmail']) )
  174. ) {
  175. $json['error'] = $container->get('translator')->trans('required fields: name ,from, message, actAsType or actAsEmail');
  176. return new JsonResponse($json, Response::HTTP_BAD_REQUEST);
  177. }
  178. if ($data) {
  179. $error = false;
  180. $message = '';
  181. $entityManager = $this->getDoctrine()->getManager();
  182. if ($data['subject'] == '') {
  183. $message = $container->get('translator')->trans("Warning! Please complete subject field value!");
  184. $statusCode = Response::HTTP_BAD_REQUEST;
  185. } elseif ($data['message'] == '') {
  186. $json['message'] = $container->get('translator')->trans("Warning! Please complete message field value!");
  187. $statusCode = Response::HTTP_BAD_REQUEST;
  188. } elseif (filter_var($data['from'], FILTER_VALIDATE_EMAIL) === false) {
  189. $json['message'] = $container->get('translator')->trans("Warning! Invalid from Email Address!");
  190. $statusCode = Response::HTTP_BAD_REQUEST;
  191. } elseif ($data['actAsType'] == '' && $data['actAsEmail'] == '') {
  192. $json['message'] = $container->get('translator')->trans("Warning! Provide atleast one parameter actAsType(agent or customer) or actAsEmail");
  193. $statusCode = Response::HTTP_BAD_REQUEST;
  194. }
  195. if (! $error) {
  196. $name = explode(' ', trim($data['name']));
  197. $ticketData['firstName'] = $name[0];
  198. $ticketData['lastName'] = isset($name[1]) ? $name[1] : '';
  199. $ticketData['role'] = 4;
  200. if (
  201. (array_key_exists('actAsType', $data))
  202. && (strtolower($data['actAsType']) == 'customer')
  203. ) {
  204. $actAsType = strtolower(trim($data['actAsType']));
  205. } else if (
  206. (array_key_exists('actAsEmail', $data))
  207. && (strtolower(trim($data['actAsType'])) == 'agent')
  208. ) {
  209. $user = $entityManager->getRepository(User::class)->findOneByEmail(trim($data['actAsEmail']));
  210. if ($user) {
  211. $actAsType = 'agent';
  212. } else {
  213. $json['error'] = $container->get('translator')->trans("Error ! actAsEmail is not valid");
  214. return new JsonResponse($json, Response::HTTP_BAD_REQUEST);
  215. }
  216. } else {
  217. $json['warning'] = $container->get('translator')->trans('Warning ! For Customer specify actAsType as customer and for Agent specify both parameter actASType as agent and actAsEmail as agent email');
  218. $statusCode = Response::HTTP_BAD_REQUEST;
  219. return new JsonResponse($json, $statusCode);
  220. }
  221. // Create customer if account does not exists
  222. $customer = $entityManager->getRepository(User::class)->findOneByEmail($data['from']);
  223. if (empty($customer) || null == $customer->getCustomerInstance()) {
  224. $role = $entityManager->getRepository(SupportRole::class)->findOneByCode('ROLE_CUSTOMER');
  225. // Create User Instance
  226. $customer = $container->get('user.service')->createUserInstance($data['from'], $data['name'], $role, [
  227. 'source' => 'api',
  228. 'active' => true
  229. ]);
  230. }
  231. if ($actAsType == 'agent') {
  232. $data['user'] = isset($user) && $user ? $user : $container->get('user.service')->getCurrentUser();
  233. } else {
  234. $data['user'] = $customer;
  235. }
  236. $attachments = $request->files->get('attachments');
  237. if (! empty($attachments)) {
  238. $attachments = is_array($attachments) ? $attachments : [$attachments];
  239. }
  240. $ticketData['user'] = $data['user'];
  241. $ticketData['subject'] = trim($data['subject']);
  242. $ticketData['message'] = trim($data['message']);
  243. $ticketData['customer'] = $customer;
  244. $ticketData['source'] = 'api';
  245. $ticketData['threadType'] = 'create';
  246. $ticketData['createdBy'] = $actAsType;
  247. $ticketData['attachments'] = $attachments;
  248. $extraKeys = ['tags', 'group', 'priority', 'status', 'agent', 'createdAt', 'updatedAt'];
  249. if (array_key_exists('type', $data)) {
  250. $ticketType = $entityManager->getRepository(TicketType::class)->findOneByCode($data['type']);
  251. $ticketData['type'] = $ticketType;
  252. }
  253. $requestData = $data;
  254. foreach ($extraKeys as $key) {
  255. if (isset($ticketData[$key])) {
  256. unset($ticketData[$key]);
  257. }
  258. }
  259. $thread = $container->get('ticket.service')->createTicketBase($ticketData);
  260. // Trigger ticket created event
  261. try {
  262. $event = new CoreWorkflowEvents\Ticket\Create();
  263. $event
  264. ->setTicket($thread->getTicket())
  265. ;
  266. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  267. } catch (\Exception $e) {
  268. //
  269. }
  270. $json['message'] = $container->get('translator')->trans('Success ! Ticket has been created successfully.');
  271. $json['ticketId'] = $thread->getTicket()->getId();
  272. $statusCode = Response::HTTP_OK;
  273. } else {
  274. $json['message'] = $container->get('translator')->trans('Warning ! Required parameters should not be blank');
  275. $statusCode = Response::HTTP_BAD_REQUEST;
  276. }
  277. } else {
  278. $json['error'] = $container->get('translator')->trans('invalid/empty size of Request');
  279. $json['message'] = $container->get('translator')->trans('Warning ! Post size can not exceed 25MB');
  280. $statusCode = Response::HTTP_BAD_REQUEST;
  281. }
  282. return new JsonResponse($json, $statusCode);
  283. }
  284. /**
  285. * View support tickets.
  286. *
  287. * @param Request $request
  288. * @return void
  289. */
  290. public function viewTicket($ticketId, Request $request, ContainerInterface $container, UVDeskService $uvdesk)
  291. {
  292. $entityManager = $this->getDoctrine()->getManager();
  293. $userRepository = $entityManager->getRepository(User::class);
  294. $ticketRepository = $entityManager->getRepository(Ticket::class);
  295. $ticket = $ticketRepository->findOneById($ticketId);
  296. if (empty($ticket)) {
  297. throw new \Exception('Page not found');
  298. }
  299. $user = $this->getUser();
  300. $userInstance = $user->getCurrentInstance();
  301. $agent = $ticket->getAgent();
  302. $customer = $ticket->getCustomer();
  303. $defaultAgentProfileImagePath = $this->getParameter('assets_default_agent_profile_image_path');
  304. $defaultCustomerProfileImagePath = $this->getParameter('assets_default_customer_profile_image_path');
  305. $agentDetails = !empty($agent) ? $agent->getAgentInstance()->getPartialDetails() : null;
  306. $customerDetails = $customer->getCustomerInstance()->getPartialDetails();
  307. if (! empty($agentDetails)) {
  308. $agentDetails['thumbnail'] = $uvdesk->generateCompleteLocalResourcePathUri($agentDetails['thumbnail'] ?? $defaultAgentProfileImagePath);
  309. }
  310. if (! empty($agentDetails)) {
  311. $customerDetails['thumbnail'] = $uvdesk->generateCompleteLocalResourcePathUri($customerDetails['thumbnail'] ?? $defaultCustomerProfileImagePath);
  312. }
  313. // Mark as viewed by agents
  314. if (false == $ticket->getIsAgentViewed()) {
  315. $ticket
  316. ->setIsAgentViewed(true)
  317. ;
  318. $entityManager->persist($ticket);
  319. $entityManager->flush();
  320. }
  321. // Ticket status Collection
  322. $status = array_map(function ($statusCollection) {
  323. return [
  324. 'id' => $statusCollection->getId(),
  325. 'code' => $statusCollection->getCode(),
  326. 'colorCode' => $statusCollection->getColorCode(),
  327. 'description' => $statusCollection->getDescription(),
  328. ];
  329. }, $entityManager->getRepository(TicketStatus::class)->findAll());
  330. // Ticket Type Collection
  331. $type = array_map(function ($ticketTypeCollection) {
  332. return [
  333. 'id' => $ticketTypeCollection->getId(),
  334. 'code' => $ticketTypeCollection->getCode(),
  335. 'isActive' => $ticketTypeCollection->getIsActive(),
  336. 'description' => $ticketTypeCollection->getDescription(),
  337. ];
  338. }, $entityManager->getRepository(TicketType::class)->findByIsActive(true));
  339. // Priority Collection
  340. $priority = array_map(function ($ticketPriorityCollection) {
  341. return [
  342. 'id' => $ticketPriorityCollection->getId(),
  343. 'code' => $ticketPriorityCollection->getCode(),
  344. 'colorCode' => $ticketPriorityCollection->getColorCode(),
  345. 'description' => $ticketPriorityCollection->getDescription(),
  346. ];
  347. }, $entityManager->getRepository(TicketPriority::class)->findAll());
  348. $userService = $container->get('user.service');
  349. $fileSystemService = $container->get('uvdesk.core.file_system.service');
  350. $supportGroup = $ticket->getSupportGroup();
  351. if (! empty($supportGroup)) {
  352. $supportGroup = [
  353. 'id' => $supportGroup->getId(),
  354. 'name' => $supportGroup->getName(),
  355. ];
  356. }
  357. $supportTeam = $ticket->getSupportTeam();
  358. if (! empty($supportTeam)) {
  359. $supportTeam = [
  360. 'id' => $supportTeam->getId(),
  361. 'name' => $supportTeam->getName(),
  362. ];
  363. }
  364. $ticketDetails = [
  365. 'id' => $ticket->getId(),
  366. 'source' => $ticket->getSource(),
  367. 'priority' => $ticket->getPriority()->getId(),
  368. 'status' => $ticket->getStatus()->getId(),
  369. 'subject' => $ticket->getSubject(),
  370. 'isNew' => $ticket->getIsNew(),
  371. 'isReplied' => $ticket->getIsReplied(),
  372. 'isReplyEnabled' => $ticket->getIsReplyEnabled(),
  373. 'isStarred' => $ticket->getIsStarred(),
  374. 'isTrashed' => $ticket->getIsTrashed(),
  375. 'isAgentViewed' => $ticket->getIsAgentViewed(),
  376. 'isCustomerViewed' => $ticket->getIsCustomerViewed(),
  377. 'createdAt' => $userService->getLocalizedFormattedTime($ticket->getCreatedAt(), $user),
  378. 'updatedAt' => $userService->getLocalizedFormattedTime($ticket->getUpdatedAt(), $user),
  379. 'group' => $supportGroup,
  380. 'team' => $supportTeam,
  381. ];
  382. $threads = array_map(function ($thread) use ($uvdesk, $userService, $fileSystemService, $defaultAgentProfileImagePath, $defaultCustomerProfileImagePath) {
  383. $user = $thread->getUser();
  384. $userInstance = $thread->getCreatedBy() == 'agent' ? $user->getAgentInstance() : $user->getCustomerInstance();
  385. $attachments = array_map(function ($attachment) use ($fileSystemService) {
  386. return $fileSystemService->getFileTypeAssociations($attachment);
  387. }, $thread->getAttachments()->getValues());
  388. $thumbnail = $uvdesk->generateCompleteLocalResourcePathUri($userInstance->getProfileImagePath() ?? ($thread->getCreatedBy() == 'agent' ? $defaultAgentProfileImagePath : $defaultCustomerProfileImagePath));
  389. return [
  390. 'id' => $thread->getId(),
  391. 'source' => $thread->getSource(),
  392. 'threadType' => $thread->getThreadType(),
  393. 'createdBy' => $thread->getCreatedBy(),
  394. 'cc' => $thread->getCc(),
  395. 'bcc' => $thread->getBcc(),
  396. 'isLocked' => $thread->getIsLocked(),
  397. 'isBookmarked' => $thread->getIsBookmarked(),
  398. 'message' => $thread->getMessage(),
  399. 'source' => $thread->getSource(),
  400. 'createdAt' => $userService->getLocalizedFormattedTime($thread->getCreatedAt(), $user),
  401. 'updatedAt' => $userService->getLocalizedFormattedTime($thread->getUpdatedAt(), $user),
  402. 'user' => [
  403. 'id' => $user->getId(),
  404. 'name' => $user->getFullName(),
  405. 'email' => $user->getEmail(),
  406. 'thumbnail' => $thumbnail,
  407. ],
  408. 'attachments' => $attachments,
  409. ];
  410. }, $ticket->getThreads()->getValues());
  411. $ticketDetails['threads'] = $threads;
  412. $ticketDetails['agent'] = $agentDetails;
  413. $ticketDetails['customer'] = $customerDetails;
  414. $ticketDetails['totalThreads'] = count($threads);
  415. return new JsonResponse([
  416. 'ticket' => $ticketDetails,
  417. 'totalCustomerTickets' => ($ticketRepository->countCustomerTotalTickets($customer, $container)),
  418. 'supportGroups' => $userRepository->getSupportGroups(),
  419. 'supportTeams' => $userRepository->getSupportTeams(),
  420. 'ticketStatuses' => $status,
  421. 'ticketPriorities' => $priority,
  422. 'ticketTypes' => $type
  423. ]);
  424. }
  425. /**
  426. * delete support tickets.
  427. *
  428. * @param Request $request
  429. * @return void
  430. */
  431. public function deleteTicketForever(Request $request, ContainerInterface $container)
  432. {
  433. $ticketId = $request->attributes->get('ticketId');
  434. $entityManager = $this->getDoctrine()->getManager();
  435. $ticket = $entityManager->getRepository(Ticket::class)->find($ticketId);
  436. if (! $ticket) {
  437. throw new NotFoundHttpException('Page Not Found');
  438. }
  439. if ($ticket->getIsTrashed()) {
  440. $entityManager->remove($ticket);
  441. $entityManager->flush();
  442. $json['success'] = $container->get('translator')->trans('Success ! Ticket removed successfully.');
  443. $statusCode = Response::HTTP_OK;
  444. // Trigger ticket delete event
  445. $event = new CoreWorkflowEvents\Ticket\Delete();
  446. $event
  447. ->setTicket($ticket)
  448. ;
  449. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  450. } else {
  451. $json['error'] = $container->get('translator')->trans('Warning ! something went wrong.');
  452. $statusCode = Response::HTTP_BAD_REQUEST;
  453. }
  454. return new JsonResponse($json, $statusCode);
  455. }
  456. /**
  457. * Assign Ticket to a agent
  458. *
  459. * @param Request $request
  460. * @return void
  461. */
  462. public function assignAgent(Request $request, ContainerInterface $container)
  463. {
  464. $json = [];
  465. $data = $request->request->all() ? :json_decode($request->getContent(), true);
  466. $ticketId = $request->attributes->get('ticketId');
  467. $entityManager = $this->getDoctrine()->getManager();
  468. $ticket = $entityManager->getRepository(Ticket::class)->findOneBy(array('id' => $ticketId));
  469. if ($ticket) {
  470. if (isset($data['id'])) {
  471. $agent = $entityManager->getRepository(User::class)->find($data['id']);
  472. } else {
  473. $json['error'] = $container->get('translator')->trans('missing fields');
  474. $json['description'] = $container->get('translator')->trans('required: id ');
  475. return new JsonResponse($json, Response::HTTP_BAD_REQUEST);
  476. }
  477. if ($agent) {
  478. if ($ticket->getAgent() != $agent) {
  479. if ($ticket->getIsTrashed()) {
  480. $json['status'] = false;
  481. $json['error'] = $container->get('translator')->trans('Tickets is in trashed can not assign to agent.');
  482. return new JsonResponse($json, Response::HTTP_BAD_REQUEST);
  483. }
  484. $ticket->setAgent($agent);
  485. $entityManager->persist($ticket);
  486. $entityManager->flush();
  487. $json['success'] = $container->get('translator')->trans('Success ! Ticket assigned to agent successfully.');
  488. $statusCode = Response::HTTP_OK;
  489. // Trigger ticket delete event
  490. $event = new CoreWorkflowEvents\Ticket\Agent();
  491. $event
  492. ->setTicket($ticket)
  493. ;
  494. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  495. } else {
  496. $json['error'] = $container->get('translator')->trans('invalid resource');
  497. $json['description'] = $container->get('translator')->trans('Error ! Invalid agent or already assigned for this ticket');
  498. $statusCode = Response::HTTP_NOT_FOUND;
  499. }
  500. }
  501. } else {
  502. $json['error'] = $container->get('translator')->trans('invalid ticket');
  503. $statusCode = Response::HTTP_NOT_FOUND;
  504. }
  505. return new JsonResponse($json, $statusCode);
  506. }
  507. /**
  508. * adding or removing collaborator to a Ticket
  509. *
  510. * @param Request $request
  511. * @return void
  512. */
  513. public function addRemoveTicketCollaborator(Request $request, ContainerInterface $container)
  514. {
  515. $json = [];
  516. $statusCode = Response::HTTP_OK;
  517. $content = $request->request->all()? : json_decode($request->getContent(), true);
  518. $entityManager = $this->getDoctrine()->getManager();
  519. $ticket = $entityManager->getRepository(Ticket::class)->find($request->attributes->get('ticketId'));
  520. if (!$ticket) {
  521. $json['error'] = $container->get('translator')->trans('resource not found');
  522. return new JsonResponse($json, Response::HTTP_NOT_FOUND);
  523. }
  524. if (
  525. $request->getMethod() == "POST"
  526. && !(isset($content['id']))
  527. ) {
  528. if (
  529. !isset($content['email'])
  530. || !filter_var($content['email'], FILTER_VALIDATE_EMAIL)
  531. ) {
  532. $json['error'] = $container->get('translator')->trans('missing/invalid field');
  533. $json['message'] = $container->get('translator')->trans('required: email');
  534. return new JsonResponse($json, Response::HTTP_BAD_REQUEST);
  535. }
  536. if ($content['email'] == $ticket->getCustomer()->getEmail()) {
  537. $json['error'] = $container->get('translator')->trans('Error ! Can not add customer as a collaborator.');
  538. $statusCode = Response::HTTP_BAD_REQUEST;
  539. } else {
  540. $data = array(
  541. 'from' => $content['email'],
  542. 'firstName' => ($firstName = ucfirst(current(explode('@', $content['email'])))),
  543. 'lastName' => '',
  544. 'role' => 4,
  545. );
  546. $supportRole = $entityManager->getRepository(SupportRole::class)->findOneByCode('ROLE_CUSTOMER');
  547. $collaborator = $container->get('user.service')->createUserInstance($data['from'], $data['firstName'], $supportRole, $extras = ["active" => true]);
  548. $checkTicket = $entityManager->getRepository(Ticket::class)->isTicketCollaborator($ticket, $content['email']);
  549. if (!$checkTicket) {
  550. $ticket->addCollaborator($collaborator);
  551. $entityManager->persist($ticket);
  552. $entityManager->flush();
  553. $ticket->lastCollaborator = $collaborator;
  554. if ($collaborator->getCustomerInstance()) {
  555. $json['collaborator'] = $collaborator->getCustomerInstance()->getPartialDetails();
  556. } else {
  557. $json['collaborator'] = $collaborator->getAgentInstance()->getPartialDetails();
  558. }
  559. $event = new CoreWorkflowEvents\Ticket\Collaborator();
  560. $event
  561. ->setTicket($ticket)
  562. ;
  563. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  564. $json['success'] = $container->get('translator')->trans('Success ! Collaborator added successfully.');
  565. $statusCode = Response::HTTP_OK;
  566. } else {
  567. $json['warning'] = $container->get('translator')->trans('Collaborator is already added.');
  568. $statusCode = Response::HTTP_BAD_REQUEST;
  569. }
  570. }
  571. } elseif ($request->getMethod() == "POST" && isset($content['id']) ) {
  572. $collaborator = $entityManager->getRepository(User::class)->findOneBy(array('id' => $content['id']));
  573. if ($collaborator) {
  574. $ticket->removeCollaborator($collaborator);
  575. $entityManager->persist($ticket);
  576. $entityManager->flush();
  577. $json['success'] = $container->get('translator')->trans('Success ! Collaborator removed successfully.');
  578. $statusCode = Response::HTTP_OK;
  579. } else {
  580. $json['error'] = $container->get('translator')->trans('Error ! Invalid Collaborator.');
  581. $statusCode = Response::HTTP_BAD_REQUEST;
  582. }
  583. }
  584. return new JsonResponse($json, $statusCode);
  585. }
  586. /**
  587. * Download ticket attachment
  588. *
  589. * @param Request $request
  590. * @return void
  591. */
  592. public function downloadAttachment(Request $request, ContainerInterface $container)
  593. {
  594. $attachmentId = $request->attributes->get('attachmentId');
  595. $attachmentRepository = $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  596. $attachment = $attachmentRepository->findOneById($attachmentId);
  597. $baseurl = $request->getScheme() . '://' . $request->getHttpHost() . $request->getBasePath();
  598. if (!$attachment) {
  599. throw new NotFoundHttpException('Page Not Found');
  600. }
  601. $path = $container->get('kernel')->getProjectDir() . "/public/". $attachment->getPath();
  602. $response = new Response();
  603. $response->setStatusCode(200);
  604. $response->headers->set('Content-type', $attachment->getContentType());
  605. $response->headers->set('Content-Disposition', 'attachment; filename='. $attachment->getName());
  606. $response->sendHeaders();
  607. $response->setContent(readfile($path));
  608. return $response;
  609. }
  610. /**
  611. * Download Zip attachment
  612. *
  613. * @param Request $request
  614. * @return void
  615. */
  616. public function downloadZipAttachment(Request $request)
  617. {
  618. $threadId = $request->attributes->get('threadId');
  619. $attachmentRepository = $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  620. $attachment = $attachmentRepository->findByThread($threadId);
  621. if (!$attachment) {
  622. throw new NotFoundHttpException('Page Not Found');
  623. }
  624. $zipname = 'attachments/' .$threadId.'.zip';
  625. $zip = new \ZipArchive;
  626. $zip->open($zipname, \ZipArchive::CREATE);
  627. if (count($attachment)) {
  628. foreach ($attachment as $attach) {
  629. $zip->addFile(substr($attach->getPath(), 1));
  630. }
  631. }
  632. $zip->close();
  633. $response = new Response();
  634. $response->setStatusCode(200);
  635. $response->headers->set('Content-type', 'application/zip');
  636. $response->headers->set('Content-Disposition', 'attachment; filename=' . $threadId . '.zip');
  637. $response->sendHeaders();
  638. $response->setContent(readfile($zipname));
  639. return $response;
  640. }
  641. /**
  642. * Edit Ticket properties
  643. *
  644. * @param Request $request
  645. * @return void
  646. */
  647. public function editTicketProperties(Request $request, ContainerInterface $container)
  648. {
  649. $json = [];
  650. $statusCode = Response::HTTP_OK;
  651. $entityManager = $this->getDoctrine()->getManager();
  652. $requestContent = $request->request->all() ?: json_decode($request->getContent(), true);
  653. $ticketId = $request->attributes->get('ticketId');
  654. $ticket = $entityManager->getRepository(Ticket::class)->findOneById($ticketId);
  655. // Validate request integrity
  656. if (empty($ticket)) {
  657. $json['error'] = 'invalid resource';
  658. $json['description'] = $container->get('translator')->trans('Unable to retrieve details for ticket #%ticketId%.', [
  659. '%ticketId%' => $ticketId,
  660. ]);
  661. $statusCode = Response::HTTP_NOT_FOUND;
  662. return new JsonResponse($json, $statusCode);
  663. } else if (!isset($requestContent['property'])) {
  664. $json['error'] = $container->get('translator')->trans('missing resource');
  665. $json['description'] = $container->get('translator')->trans('Insufficient details provided.');
  666. $statusCode = Response::HTTP_BAD_REQUEST;
  667. return new JsonResponse($json, $statusCode);
  668. }
  669. // Update property
  670. switch ($requestContent['property']) {
  671. case 'agent':
  672. $agent = $entityManager->getRepository(User::class)->findOneById($requestContent['value']);
  673. if (empty($agent)) {
  674. // User does not exist
  675. $json['error'] = $container->get('translator')->trans('No such user exist');
  676. $json['description'] = $container->get('translator')->trans('Unable to retrieve agent details');
  677. $statusCode = Response::HTTP_BAD_REQUEST;
  678. return new JsonResponse($json, $statusCode);
  679. } else {
  680. // Check if an agent instance exists for the user
  681. $agentInstance = $agent->getAgentInstance();
  682. if (empty($agentInstance)) {
  683. // Agent does not exist
  684. $json['error'] = $container->get('translator')->trans('No such user exist');
  685. $json['description'] = $container->get('translator')->trans('Unable to retrieve agent details');
  686. $statusCode = Response::HTTP_BAD_REQUEST;
  687. return new JsonResponse($json, $statusCode);
  688. }
  689. }
  690. $agentDetails = $agentInstance->getPartialDetails();
  691. // Check if ticket is already assigned to the agent
  692. if (
  693. $ticket->getAgent()
  694. && $agent->getId() === $ticket->getAgent()->getId()
  695. ) {
  696. $json['success'] = $container->get('translator')->trans('Already assigned');
  697. $json['description'] = $container->get('translator')->trans('Ticket already assigned to %agent%', [
  698. '%agent%' => $agentDetails['name']]);
  699. $statusCode = Response::HTTP_OK;
  700. return new JsonResponse($json, $statusCode);
  701. } else {
  702. $ticket->setAgent($agent);
  703. $entityManager->persist($ticket);
  704. $entityManager->flush();
  705. // Trigger Agent Assign event
  706. $event = new CoreWorkflowEvents\Ticket\Agent();
  707. $event
  708. ->setTicket($ticket)
  709. ;
  710. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  711. $json['success'] = $container->get('translator')->trans('Success');
  712. $json['description'] = $container->get('translator')->trans('Ticket successfully assigned to %agent%', [
  713. '%agent%' => $agentDetails['name'],
  714. ]);
  715. $statusCode = Response::HTTP_OK;
  716. return new JsonResponse($json, $statusCode);
  717. }
  718. break;
  719. case 'status':
  720. $ticketStatus = $entityManager->getRepository(TicketStatus::class)->findOneById((int) $requestContent['value']);
  721. if (empty($ticketStatus)) {
  722. // Selected ticket status does not exist
  723. $json['error'] = $container->get('translator')->trans('Error');
  724. $json['description'] = $container->get('translator')->trans('Unable to retrieve status details');
  725. $statusCode = Response::HTTP_BAD_REQUEST;
  726. return new JsonResponse($json, $statusCode);
  727. }
  728. if ($ticketStatus->getId() === $ticket->getStatus()->getId()) {
  729. $json['success'] = $container->get('translator')->trans('Success');
  730. $json['description'] = $container->get('translator')->trans('Ticket status already set to %status%', [
  731. '%status%' => $ticketStatus->getDescription()]);
  732. $statusCode = Response::HTTP_OK;
  733. return new JsonResponse($json, $statusCode);
  734. } else {
  735. $ticket->setStatus($ticketStatus);
  736. $entityManager->persist($ticket);
  737. $entityManager->flush();
  738. // Trigger ticket status event
  739. $event = new CoreWorkflowEvents\Ticket\Status();
  740. $event
  741. ->setTicket($ticket)
  742. ;
  743. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  744. $json['success'] = $container->get('translator')->trans('Success');
  745. $json['description'] = $container->get('translator')->trans('Ticket status update to %status%', [
  746. '%status%' => $ticketStatus->getDescription()]);
  747. $statusCode = Response::HTTP_OK;
  748. return new JsonResponse($json, $statusCode);
  749. }
  750. break;
  751. case 'priority':
  752. // $container->isAuthorized('ROLE_AGENT_UPDATE_TICKET_PRIORITY');
  753. $ticketPriority = $entityManager->getRepository(TicketPriority::class)->findOneById($requestContent['value']);
  754. if (empty($ticketPriority)) {
  755. // Selected ticket priority does not exist
  756. $json['error'] = $container->get('translator')->trans('Error');
  757. $json['description'] = $container->get('translator')->trans('Unable to retrieve priority details');
  758. $statusCode = Response::HTTP_BAD_REQUEST;
  759. return new JsonResponse($json, $statusCode);
  760. }
  761. if ($ticketPriority->getId() === $ticket->getPriority()->getId()) {
  762. $json['success'] = $container->get('translator')->trans('Success');
  763. $json['description'] = $container->get('translator')->trans('Ticket priority already set to %priority%', [
  764. '%priority%' => $ticketPriority->getDescription()
  765. ]);
  766. $statusCode = Response::HTTP_OK;
  767. return new JsonResponse($json, $statusCode);
  768. } else {
  769. $ticket->setPriority($ticketPriority);
  770. $entityManager->persist($ticket);
  771. $entityManager->flush();
  772. // Trigger ticket Priority event
  773. $event = new CoreWorkflowEvents\Ticket\Priority();
  774. $event
  775. ->setTicket($ticket)
  776. ;
  777. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  778. $json['success'] = $container->get('translator')->trans('Success');
  779. $json['description'] = $container->get('translator')->trans('Ticket priority updated to %priority%', [
  780. '%priority%' => $ticketPriority->getDescription()
  781. ]);
  782. $statusCode = Response::HTTP_OK;
  783. return new JsonResponse($json, $statusCode);
  784. }
  785. break;
  786. case 'group':
  787. $supportGroup = $entityManager->getRepository(SupportGroup::class)->findOneById($requestContent['value']);
  788. if (empty($supportGroup)) {
  789. if ($requestContent['value'] == "") {
  790. if ($ticket->getSupportGroup() != null) {
  791. $ticket->setSupportGroup(null);
  792. $entityManager->persist($ticket);
  793. $entityManager->flush();
  794. }
  795. $json['success'] = $container->get('translator')->trans('Success');
  796. $json['description'] = $container->get('translator')->trans('Ticket support group updated successfully');
  797. $statusCode = Response::HTTP_OK;
  798. } else {
  799. $json['error'] = $container->get('translator')->trans('Error');
  800. $json['description'] = $container->get('translator')->trans('Unable to retrieve support group details');
  801. $statusCode = Response::HTTP_BAD_REQUEST;
  802. }
  803. return new JsonResponse($json, $statusCode);
  804. }
  805. if (
  806. ! empty($ticket->getSupportGroup())
  807. && $supportGroup->getId() === $ticket->getSupportGroup()->getId()
  808. ) {
  809. $json['success'] = $container->get('translator')->trans('Success');
  810. $json['description'] = $container->get('translator')->trans('Ticket already assigned to support group');
  811. $statusCode = Response::HTTP_OK;
  812. return new JsonResponse($json, $statusCode);
  813. } else {
  814. $ticket->setSupportGroup($supportGroup);
  815. $entityManager->persist($ticket);
  816. $entityManager->flush();
  817. // Trigger Support group event
  818. $event = new CoreWorkflowEvents\Ticket\Group();
  819. $event
  820. ->setTicket($ticket)
  821. ;
  822. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  823. $json['success'] = $container->get('translator')->trans('Success');
  824. $json['description'] = $container->get('translator')->trans('Ticket assigned to support group successfully');
  825. $json['description'] = $container->get('translator')->trans('Ticket assigned to support group %group%', [
  826. '%group%' => $supportGroup->getDescription()
  827. ]);
  828. $statusCode = Response::HTTP_OK;
  829. return new JsonResponse($json, $statusCode);
  830. }
  831. break;
  832. case 'team':
  833. $supportTeam = $entityManager->getRepository(SupportTeam::class)->findOneById($requestContent['value']);
  834. if (empty($supportTeam)) {
  835. if ($requestContent['value'] == "") {
  836. if ($ticket->getSupportTeam() != null) {
  837. $ticket->setSupportTeam(null);
  838. $entityManager->persist($ticket);
  839. $entityManager->flush();
  840. }
  841. $json['success'] = $container->get('translator')->trans('Success');
  842. $json['description'] = $container->get('translator')->trans('Ticket support team updated successfully');
  843. $statusCode = Response::HTTP_OK;
  844. return new JsonResponse($json, $statusCode);
  845. } else {
  846. $json['error'] = $container->get('translator')->trans('Error');
  847. $json['description'] = $container->get('translator')->trans('Unable to retrieve support team details');
  848. $statusCode = Response::HTTP_BAD_REQUEST;
  849. return new JsonResponse($json, $statusCode);
  850. }
  851. }
  852. if (
  853. ! empty($ticket->getSupportTeam())
  854. && $supportTeam->getId() === $ticket->getSupportTeam()->getId()
  855. ) {
  856. $json['success'] = $container->get('translator')->trans('Success');
  857. $json['description'] = $container->get('translator')->trans('Ticket already assigned to support team');
  858. $statusCode = Response::HTTP_OK;
  859. return new JsonResponse($json, $statusCode);
  860. } else {
  861. $ticket->setSupportTeam($supportTeam);
  862. $entityManager->persist($ticket);
  863. $entityManager->flush();
  864. // Trigger ticket delete event
  865. $event = new CoreWorkflowEvents\Ticket\Team();
  866. $event
  867. ->setTicket($ticket)
  868. ;
  869. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  870. $json['success'] = $container->get('translator')->trans('Success');
  871. $json['description'] = $container->get('translator')->trans('Ticket assigned to support team successfully');
  872. $json['description'] = $container->get('translator')->trans('Ticket assigned to support team %team%', [
  873. '%team%' => $supportTeam->getDescription()
  874. ]);
  875. $statusCode = Response::HTTP_OK;
  876. return new JsonResponse($json, $statusCode);
  877. }
  878. break;
  879. case 'type':
  880. // $container->isAuthorized('ROLE_AGENT_UPDATE_TICKET_TYPE');
  881. $ticketType = $entityManager->getRepository(TicketType::class)->findOneById($requestContent['value']);
  882. if (empty($ticketType)) {
  883. // Selected ticket priority does not exist
  884. $json['error'] = $container->get('translator')->trans('Error');
  885. $json['description'] = $container->get('translator')->trans('Unable to retrieve ticket type details');
  886. $statusCode = Response::HTTP_BAD_REQUEST;
  887. return new JsonResponse($json, $statusCode);
  888. }
  889. if (
  890. ! empty($ticket->getType())
  891. && $ticketType->getId() === $ticket->getType()->getId()
  892. ) {
  893. $json['success'] = $container->get('translator')->trans('Success');
  894. $json['description'] = $container->get('translator')->trans('Ticket type already set to ' . $ticketType->getDescription());
  895. $statusCode = Response::HTTP_OK;
  896. return new JsonResponse($json, $statusCode);
  897. } else {
  898. $ticket->setType($ticketType);
  899. $entityManager->persist($ticket);
  900. $entityManager->flush();
  901. // Trigger ticket delete event
  902. $event = new CoreWorkflowEvents\Ticket\Type();
  903. $event
  904. ->setTicket($ticket)
  905. ;
  906. $container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  907. $json['success'] = $container->get('translator')->trans('Success');
  908. $json['description'] = $container->get('translator')->trans('Ticket type updated to ' . $ticketType->getDescription());
  909. $statusCode = Response::HTTP_OK;
  910. return new JsonResponse($json, $statusCode);
  911. }
  912. break;
  913. case 'label':
  914. $label = $entityManager->getRepository(SupportLabel::class)->find($requestContent['value']);
  915. if ($label) {
  916. $ticket->removeSupportLabel($label);
  917. $entityManager->persist($ticket);
  918. $entityManager->flush();
  919. $json['success'] = $container->get('translator')->trans('Success');
  920. $json['description'] = $container->get('translator')->trans('Success ! Ticket to label removed successfully');
  921. $statusCode = Response::HTTP_OK;
  922. return new JsonResponse($json, $statusCode);
  923. } else {
  924. $json['error'] = $container->get('translator')->trans('Error');
  925. $json['description'] = $container->get('translator')->trans('No support level exist for this ticket with this id');
  926. $statusCode = Response::HTTP_BAD_REQUEST;
  927. return new JsonResponse($json, $statusCode);
  928. }
  929. break;
  930. default:
  931. break;
  932. }
  933. return new JsonResponse($json, $statusCode);
  934. }
  935. /**
  936. * objectSerializer This function convert Entity object into json contenxt
  937. * @param Object $object Customer Entity object
  938. * @return JSON JSON context
  939. */
  940. public function objectSerializer($object) {
  941. $object->formatedCreatedAt = new \Datetime;
  942. $encoders = array(new XmlEncoder(), new JsonEncoder());
  943. $normalizer = new ObjectNormalizer();
  944. $normalizers = array($normalizer);
  945. $serializer = new Serializer($normalizers, $encoders);
  946. $jsonContent = $serializer->serialize($object, 'json', [
  947. 'circular_reference_handler' => function ($object) {
  948. return $object->getId();
  949. }
  950. ]);
  951. return $jsonContent;
  952. }
  953. }