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

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