vendor/uvdesk/core-framework/Services/TicketService.php line 760

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\CoreFrameworkBundle\Services;
  3. use Doctrine\ORM\Query;
  4. use Symfony\Component\Yaml\Yaml;
  5. use Doctrine\ORM\EntityManagerInterface;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use Symfony\Component\HttpFoundation\Response;
  8. use Symfony\Component\HttpFoundation\RequestStack;
  9. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  10. use Webkul\UVDesk\CoreFrameworkBundle\Entity\AgentActivity;
  11. use Webkul\UVDesk\MailboxBundle\Utils\Mailbox\Mailbox;
  12. use Symfony\Component\EventDispatcher\GenericEvent;
  13. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Thread;
  15. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Tag;
  16. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketType;
  17. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketStatus;
  18. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketPriority;
  19. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportRole;
  20. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Website;
  21. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportGroup;
  22. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportTeam;
  23. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportLabel;
  24. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SavedReplies;
  25. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Attachment;
  26. use Webkul\UVDesk\MailboxBundle\Utils\MailboxConfiguration;
  27. use Webkul\UVDesk\CoreFrameworkBundle\Utils\TokenGenerator;
  28. use Symfony\Component\DependencyInjection\ContainerInterface;
  29. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  30. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  31. use Webkul\UVDesk\CoreFrameworkBundle\Services\FileUploadService;
  32. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  33. use UVDesk\CommunityPackages\UVDesk\FormComponent\Entity;
  34. use Webkul\UVDesk\MailboxBundle\Utils\Imap\Configuration as ImapConfiguration;
  35. use Symfony\Component\Filesystem\Filesystem;
  36. use Webkul\UVDesk\SupportCenterBundle\Entity\Article;
  37. use Webkul\UVDesk\SupportCenterBundle\Entity\KnowledgebaseWebsite;
  38. use Webkul\UVDesk\AutomationBundle\Entity\PreparedResponses;
  39. use UVDesk\CommunityPackages\UVDesk as UVDeskCommunityPackages;
  40. class TicketService
  41. {
  42. const PATH_TO_CONFIG = '/config/packages/uvdesk_mailbox.yaml';
  43. protected $container;
  44. protected $requestStack;
  45. protected $entityManager;
  46. protected $fileUploadService;
  47. protected $userService;
  48. public function __construct(
  49. ContainerInterface $container,
  50. RequestStack $requestStack,
  51. EntityManagerInterface $entityManager,
  52. FileUploadService $fileUploadService,
  53. UserService $userService)
  54. {
  55. $this->container = $container;
  56. $this->requestStack = $requestStack;
  57. $this->entityManager = $entityManager;
  58. $this->fileUploadService = $fileUploadService;
  59. $this->userService = $userService;
  60. }
  61. public function getAllMailboxes()
  62. {
  63. $collection = array_map(function ($mailbox) {
  64. return [
  65. 'id' => $mailbox->getId(),
  66. 'name' => $mailbox->getName(),
  67. 'isEnabled' => $mailbox->getIsEnabled(),
  68. 'email' => $mailbox->getImapConfiguration()->getUsername(),
  69. ];
  70. }, $this->parseMailboxConfigurations()->getMailboxes());
  71. return $collection;
  72. }
  73. public function parseMailboxConfigurations(bool $ignoreInvalidAttributes = false)
  74. {
  75. $path = $this->getPathToConfigurationFile();
  76. if (!file_exists($path)) {
  77. throw new \Exception("File '$path' not found.");
  78. }
  79. // Read configurations from package config.
  80. $mailboxConfiguration = new MailboxConfiguration();
  81. $swiftmailerService = $this->container->get('swiftmailer.service');
  82. $swiftmailerConfigurations = $swiftmailerService->parseSwiftMailerConfigurations();
  83. foreach (Yaml::parse(file_get_contents($path))['uvdesk_mailbox']['mailboxes'] ?? [] as $id => $params) {
  84. // Swiftmailer Configuration
  85. $swiftmailerConfiguration = null;
  86. foreach ($swiftmailerConfigurations as $configuration) {
  87. if ($configuration->getId() == $params['smtp_server']['mailer_id']) {
  88. $swiftmailerConfiguration = $configuration;
  89. break;
  90. }
  91. }
  92. // IMAP Configuration
  93. ($imapConfiguration = ImapConfiguration::guessTransportDefinition($params['imap_server']['host']))
  94. ->setUsername($params['imap_server']['username'])
  95. ->setPassword($params['imap_server']['password']);
  96. // Mailbox Configuration
  97. ($mailbox = new Mailbox($id))
  98. ->setName($params['name'])
  99. ->setIsEnabled($params['enabled'])
  100. ->setImapConfiguration($imapConfiguration);
  101. if (!empty($swiftmailerConfiguration)) {
  102. $mailbox->setSwiftMailerConfiguration($swiftmailerConfiguration);
  103. } else if (!empty($params['smtp_server']['mailer_id']) && true === $ignoreInvalidAttributes) {
  104. $mailbox->setSwiftMailerConfiguration($swiftmailerService->createConfiguration('smtp', $params['smtp_server']['mailer_id']));
  105. }
  106. $mailboxConfiguration->addMailbox($mailbox);
  107. }
  108. return $mailboxConfiguration;
  109. }
  110. public function getPathToConfigurationFile()
  111. {
  112. return $this->container->get('kernel')->getProjectDir() . self::PATH_TO_CONFIG;
  113. }
  114. public function getRandomRefrenceId($email = null)
  115. {
  116. $email = !empty($email) ? $email : $this->container->getParameter('uvdesk.support_email.id');
  117. $emailDomain = substr($email, strpos($email, '@'));
  118. return sprintf("<%s%s>", TokenGenerator::generateToken(20, '0123456789abcdefghijklmnopqrstuvwxyz'), $emailDomain);
  119. }
  120. // @TODO: Refactor this out of this service. Use UserService::getSessionUser() instead.
  121. public function getUser()
  122. {
  123. return $this->container->get('user.service')->getCurrentUser();
  124. }
  125. public function getDefaultType()
  126. {
  127. $typeCode = $this->container->getParameter('uvdesk.default.ticket.type');
  128. $ticketType = $this->entityManager->getRepository(TicketType::class)->findOneByCode($typeCode);
  129. return !empty($ticketType) ? $ticketType : null;
  130. }
  131. public function getDefaultStatus()
  132. {
  133. $statusCode = $this->container->getParameter('uvdesk.default.ticket.status');
  134. $ticketStatus = $this->entityManager->getRepository(TicketStatus::class)->findOneByCode($statusCode);
  135. return !empty($ticketStatus) ? $ticketStatus : null;
  136. }
  137. public function getDefaultPriority()
  138. {
  139. $priorityCode = $this->container->getParameter('uvdesk.default.ticket.priority');
  140. $ticketPriority = $this->entityManager->getRepository(TicketPriority::class)->findOneByCode($priorityCode);
  141. return !empty($ticketPriority) ? $ticketPriority : null;
  142. }
  143. public function appendTwigSnippet($snippet = '')
  144. {
  145. switch ($snippet) {
  146. case 'createMemberTicket':
  147. return $this->getMemberCreateTicketSnippet();
  148. break;
  149. default:
  150. break;
  151. }
  152. return '';
  153. }
  154. public function getMemberCreateTicketSnippet()
  155. {
  156. $twigTemplatingEngine = $this->container->get('twig');
  157. $ticketTypeCollection = $this->entityManager->getRepository(TicketType::class)->findByIsActive(true);
  158. try {
  159. if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  160. $headerCustomFields = $this->container->get('uvdesk_package_custom_fields.service')->getCustomFieldsArray('user');
  161. } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  162. $headerCustomFields = $this->container->get('uvdesk_package_form_component.service')->getCustomFieldsArray('user');
  163. }
  164. } catch (\Exception $e) {
  165. // @TODO: Log execption message
  166. }
  167. return $twigTemplatingEngine->render('@UVDeskCoreFramework/Snippets/createMemberTicket.html.twig', [
  168. 'ticketTypeCollection' => $ticketTypeCollection,
  169. 'headerCustomFields' => $headerCustomFields ?? null,
  170. ]);
  171. }
  172. public function getCustomerCreateTicketCustomFieldSnippet()
  173. {
  174. try {
  175. if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  176. $customFields = $this->container->get('uvdesk_package_custom_fields.service')->getCustomFieldsArray('customer');
  177. } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  178. $customFields = $this->container->get('uvdesk_package_form_component.service')->getCustomFieldsArray('customer');
  179. }
  180. } catch (\Exception $e) {
  181. // @TODO: Log execption message
  182. }
  183. return $customFields ?? null;
  184. }
  185. public function createTicket(array $params = [])
  186. {
  187. $thread = $this->entityManager->getRepository(Thread::class)->findOneByMessageId($params['messageId']);
  188. if (empty($thread)) {
  189. $user = $this->entityManager->getRepository(User::class)->findOneByEmail($params['from']);
  190. if (empty($user) || null == $user->getCustomerInstance()) {
  191. $role = $this->entityManager->getRepository(SupportRole::class)->findOneByCode($params['role']);
  192. if (empty($role)) {
  193. throw new \Exception("The requested role '" . $params['role'] . "' does not exist.");
  194. }
  195. // Create User Instance
  196. $user = $this->container->get('user.service')->createUserInstance($params['from'], $params['name'], $role, [
  197. 'source' => strtolower($params['source']),
  198. 'active' => true,
  199. ]);
  200. }
  201. $params['role'] = 4;
  202. $params['customer'] = $params['user'] = $user;
  203. return $this->createTicketBase($params);
  204. }
  205. return;
  206. }
  207. public function createTicketBase(array $ticketData = [])
  208. {
  209. if ('email' == $ticketData['source']) {
  210. try {
  211. if (array_key_exists('UVDeskMailboxBundle', $this->container->getParameter('kernel.bundles'))) {
  212. $mailbox = $this->container->get('uvdesk.mailbox')->getMailboxByEmail($ticketData['mailboxEmail']);
  213. $ticketData['mailboxEmail'] = $mailbox['email'];
  214. }
  215. } catch (\Exception $e) {
  216. // No mailbox found for this email. Skip ticket creation.
  217. return;
  218. }
  219. }
  220. // Set Defaults
  221. $ticketType = !empty($ticketData['type']) ? $ticketData['type'] : $this->getDefaultType();
  222. $ticketStatus = !empty($ticketData['status']) ? $ticketData['status'] : $this->getDefaultStatus();
  223. $ticketPriority = !empty($ticketData['priority']) ? $ticketData['priority'] : $this->getDefaultPriority();
  224. $ticketMessageId = 'email' == $ticketData['source'] ? (!empty($ticketData['messageId']) ? $ticketData['messageId'] : null) : $this->getRandomRefrenceId();
  225. $ticketData['type'] = $ticketType;
  226. $ticketData['status'] = $ticketStatus;
  227. $ticketData['priority'] = $ticketPriority;
  228. $ticketData['messageId'] = $ticketMessageId;
  229. $ticketData['isTrashed'] = false;
  230. $ticket = new Ticket();
  231. foreach ($ticketData as $property => $value) {
  232. $callable = 'set' . ucwords($property);
  233. if (method_exists($ticket, $callable)) {
  234. $ticket->$callable($value);
  235. }
  236. }
  237. $this->entityManager->persist($ticket);
  238. $this->entityManager->flush();
  239. return $this->createThread($ticket, $ticketData);
  240. }
  241. public function createThread(Ticket $ticket, array $threadData)
  242. {
  243. $threadData['isLocked'] = 0;
  244. if ('forward' === $threadData['threadType']) {
  245. $threadData['replyTo'] = $threadData['to'];
  246. }
  247. $collaboratorEmails = array_merge(!empty($threadData['cccol']) ? $threadData['cccol'] : [], !empty($threadData['cc']) ? $threadData['cc'] : []);
  248. if (!empty($collaboratorEmails)) {
  249. $threadData['cc'] = $collaboratorEmails;
  250. }
  251. $thread = new Thread();
  252. $thread->setTicket($ticket);
  253. $thread->setCreatedAt(new \DateTime());
  254. $thread->setUpdatedAt(new \DateTime());
  255. if ($threadData['threadType'] != "note") {
  256. foreach ($threadData as $property => $value) {
  257. if (!empty($value)) {
  258. $callable = 'set' . ucwords($property);
  259. if (method_exists($thread, $callable)) {
  260. $thread->$callable($value);
  261. }
  262. }
  263. }
  264. } else {
  265. $this->setTicketNotePlaceholderValue($thread, $threadData, $ticket);
  266. }
  267. // Update ticket reference ids is thread message id is defined
  268. if (null != $thread->getMessageId() && false === strpos($ticket->getReferenceIds(), $thread->getMessageId())) {
  269. $updatedReferenceIds = $ticket->getReferenceIds() . ' ' . $thread->getMessageId();
  270. $ticket->setReferenceIds($updatedReferenceIds);
  271. $this->entityManager->persist($ticket);
  272. }
  273. if ('reply' === $threadData['threadType']) {
  274. if ('agent' === $threadData['createdBy']) {
  275. // Ticket has been updated by support agents, mark as agent replied | customer view pending
  276. $ticket->setIsCustomerViewed(false);
  277. $ticket->setIsReplied(true);
  278. $customerName = $ticket->getCustomer()->getFirstName().' '.$ticket->getCustomer()->getLastName();
  279. $agentActivity = new AgentActivity();
  280. $agentActivity->setThreadType('reply');
  281. $agentActivity->setTicket($ticket);
  282. $agentActivity->setAgent($thread->getUser());
  283. $agentActivity->setCustomerName($customerName);
  284. $agentActivity->setAgentName('agent');
  285. $agentActivity->setCreatedAt(new \DateTime());
  286. $this->entityManager->persist($agentActivity);
  287. } else {
  288. // Ticket has been updated by customer, mark as agent view | reply pending
  289. $ticket->setIsAgentViewed(false);
  290. $ticket->setIsReplied(false);
  291. }
  292. $this->entityManager->persist($ticket);
  293. } else if ('create' === $threadData['threadType']) {
  294. $ticket->setIsReplied(false);
  295. $this->entityManager->persist($ticket);
  296. $customerName = $ticket->getCustomer()->getFirstName().' '.$ticket->getCustomer()->getLastName();
  297. $agentActivity = new AgentActivity();
  298. $agentActivity->setThreadType('create');
  299. $agentActivity->setTicket($ticket);
  300. $agentActivity->setAgent($thread->getUser());
  301. $agentActivity->setCustomerName($customerName );
  302. $agentActivity->setAgentName('agent');
  303. $agentActivity->setCreatedAt(new \DateTime());
  304. $this->entityManager->persist($agentActivity);
  305. }
  306. $ticket->currentThread = $this->entityManager->getRepository(Thread::class)->getTicketCurrentThread($ticket);
  307. $this->entityManager->persist($thread);
  308. $this->entityManager->flush();
  309. $ticket->createdThread = $thread;
  310. // Uploading Attachments
  311. if (!empty($threadData['attachments'])) {
  312. if ('email' == $threadData['source']) {
  313. $this->saveThreadEmailAttachments($thread, $threadData['attachments']);
  314. } else if (!empty($threadData['attachments'])) {
  315. $this->saveThreadAttachment($thread, $threadData['attachments']);
  316. }
  317. }
  318. return $thread;
  319. }
  320. public function setTicketNotePlaceholderValue($thread, $threadData, $ticket)
  321. {
  322. if (!empty($threadData)) {
  323. foreach ($threadData as $property => $value) {
  324. if (!empty($value)) {
  325. $callable = 'set' . ucwords($property);
  326. if (method_exists($thread, $callable)) {
  327. if($callable != "setMessage") {
  328. $thread->$callable($value);
  329. } else {
  330. $notesPlaceholders = $this->getNotePlaceholderValues($ticket, 'customer');
  331. $content = $value;
  332. foreach ($notesPlaceholders as $key => $val) {
  333. if(strpos($value, "{%$key%}") !== false){
  334. $content = strtr($value, ["{%$key%}" => $val, "{% $key %}" => $val]);
  335. }
  336. }
  337. $content = stripslashes($content);
  338. $thread->$callable($content);
  339. }
  340. }
  341. }
  342. }
  343. }
  344. }
  345. public function saveThreadAttachment($thread, array $attachments)
  346. {
  347. $prefix = 'threads/' . $thread->getId();
  348. $uploadManager = $this->container->get('uvdesk.core.file_system.service')->getUploadManager();
  349. foreach ($attachments as $attachment) {
  350. $uploadedFileAttributes = $uploadManager->uploadFile($attachment, $prefix);
  351. if (!empty($uploadedFileAttributes['path'])) {
  352. ($threadAttachment = new Attachment())
  353. ->setThread($thread)
  354. ->setName($uploadedFileAttributes['name'])
  355. ->setPath($uploadedFileAttributes['path'])
  356. ->setSize($uploadedFileAttributes['size'])
  357. ->setContentType($uploadedFileAttributes['content-type']);
  358. $this->entityManager->persist($threadAttachment);
  359. }
  360. }
  361. $this->entityManager->flush();
  362. }
  363. public function saveThreadEmailAttachments($thread, array $attachments)
  364. {
  365. $prefix = 'threads/' . $thread->getId();
  366. $uploadManager = $this->container->get('uvdesk.core.file_system.service')->getUploadManager();
  367. // Upload thread attachments
  368. foreach ($attachments as $attachment) {
  369. $uploadedFileAttributes = $uploadManager->uploadEmailAttachment($attachment, $prefix);
  370. if (!empty($uploadedFileAttributes['path'])) {
  371. ($threadAttachment = new Attachment())
  372. ->setThread($thread)
  373. ->setName($uploadedFileAttributes['name'])
  374. ->setPath($uploadedFileAttributes['path'])
  375. ->setSize($uploadedFileAttributes['size'])
  376. ->setContentType($uploadedFileAttributes['content-type']);
  377. $this->entityManager->persist($threadAttachment);
  378. }
  379. }
  380. $this->entityManager->flush();
  381. }
  382. public function getTypes()
  383. {
  384. static $types;
  385. if (null !== $types)
  386. return $types;
  387. $qb = $this->entityManager->createQueryBuilder();
  388. $qb->select('tp.id','tp.code As name')->from(TicketType::class, 'tp')
  389. ->andwhere('tp.isActive = 1')
  390. ->orderBy('tp.code', 'ASC');
  391. return $types = $qb->getQuery()->getArrayResult();
  392. }
  393. public function getStatus()
  394. {
  395. static $statuses;
  396. if (null !== $statuses)
  397. return $statuses;
  398. $qb = $this->entityManager->createQueryBuilder();
  399. $qb->select('ts')->from(TicketStatus::class, 'ts');
  400. // $qb->orderBy('ts.sortOrder', Criteria::ASC);
  401. return $statuses = $qb->getQuery()->getArrayResult();
  402. }
  403. public function getTicketTotalThreads($ticketId)
  404. {
  405. $qb = $this->entityManager->createQueryBuilder();
  406. $qb->select('COUNT(th.id) as threadCount')->from(Ticket::class, 't')
  407. ->leftJoin('t.threads', 'th')
  408. ->andWhere('t.id = :ticketId')
  409. ->andWhere('th.threadType = :threadType')
  410. ->setParameter('threadType','reply')
  411. ->setParameter('ticketId', $ticketId);
  412. $qb = $this->entityManager->createQueryBuilder();
  413. $qb->select('COUNT(t.id) as threadCount')->from(Thread::class, 't')
  414. ->andWhere('t.ticket = :ticketId')
  415. ->andWhere('t.threadType = :threadType')
  416. ->setParameter('threadType','reply')
  417. ->setParameter('ticketId', $ticketId);
  418. return $qb->getQuery()->getSingleScalarResult();
  419. }
  420. public function getTicketTags($request = null)
  421. {
  422. $qb = $this->entityManager->createQueryBuilder();
  423. $qb->select('tg')->from(Tag::class, 'tg');
  424. if($request) {
  425. $qb->andwhere("tg.name LIKE :tagName");
  426. $qb->setParameter('tagName', '%'.urldecode($request->query->get('query')).'%');
  427. $qb->andwhere("tg.id NOT IN (:ids)");
  428. $qb->setParameter('ids', explode(',',urldecode($request->query->get('not'))));
  429. }
  430. return $qb->getQuery()->getArrayResult();
  431. }
  432. public function paginateMembersTicketCollection(Request $request)
  433. {
  434. $params = $request->query->all();
  435. $activeUser = $this->container->get('user.service')->getSessionUser();
  436. $activeUserTimeZone = $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'Knowledgebase']);
  437. $agentTimeZone = !empty($activeUser->getTimezone()) ? $activeUser->getTimezone() : $activeUserTimeZone->getTimezone();
  438. $agentTimeFormat = !empty($activeUser->getTimeformat()) ? $activeUser->getTimeformat() : $activeUserTimeZone->getTimeformat();
  439. $ticketRepository = $this->entityManager->getRepository(Ticket::class);
  440. $website = $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'helpdesk']);
  441. $timeZone = $website->getTimezone();
  442. $timeFormat = $website->getTimeformat();
  443. $supportGroupReference = $this->entityManager->getRepository(User::class)->getUserSupportGroupReferences($activeUser);
  444. $supportTeamReference = $this->entityManager->getRepository(User::class)->getUserSupportTeamReferences($activeUser);
  445. // Get base query
  446. $baseQuery = $ticketRepository->prepareBaseTicketQuery($activeUser, $supportGroupReference, $supportTeamReference, $params);
  447. $ticketTabs = $ticketRepository->getTicketTabDetails($activeUser, $supportGroupReference, $supportTeamReference, $params);
  448. // Apply Pagination
  449. $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  450. $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $ticketRepository::DEFAULT_PAGINATION_LIMIT;
  451. if (isset($params['repliesLess']) || isset($params['repliesMore'])) {
  452. $paginationOptions = ['wrap-queries' => true];
  453. $paginationQuery = $baseQuery->getQuery()
  454. ->setHydrationMode(Query::HYDRATE_ARRAY);
  455. } else {
  456. $paginationOptions = ['distinct' => true];
  457. $paginationQuery = $baseQuery->getQuery()
  458. ->setHydrationMode(Query::HYDRATE_ARRAY)
  459. ->setHint('knp_paginator.count', isset($params['status']) ? $ticketTabs[$params['status']] : $ticketTabs[1]);
  460. }
  461. $pagination = $this->container->get('knp_paginator')->paginate($paginationQuery, $pageNumber, $itemsLimit, $paginationOptions);
  462. // Process Pagination Response
  463. $ticketCollection = [];
  464. $paginationParams = $pagination->getParams();
  465. $paginationData = $pagination->getPaginationData();
  466. $paginationParams['page'] = 'replacePage';
  467. $paginationData['url'] = '#' . $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  468. // $container->get('default.service')->buildSessionUrl('ticket',$queryParameters);
  469. $ticketThreadCountQueryTemplate = $this->entityManager->createQueryBuilder()
  470. ->select('COUNT(thread.id) as threadCount')
  471. ->from(Ticket::class, 'ticket')
  472. ->leftJoin('ticket.threads', 'thread')
  473. ->where('ticket.id = :ticketId')
  474. ->andWhere('thread.threadType = :threadType')->setParameter('threadType', 'reply');
  475. foreach ($pagination->getItems() as $ticketDetails) {
  476. $ticket = array_shift($ticketDetails);
  477. $ticketThreadCountQuery = clone $ticketThreadCountQueryTemplate;
  478. $ticketThreadCountQuery->setParameter('ticketId', $ticket['id']);
  479. $totalTicketReplies = (int) $ticketThreadCountQuery->getQuery()->getSingleScalarResult();
  480. $ticketHasAttachments = false;
  481. $dbTime = $ticket['createdAt'];
  482. $formattedTime= $this->fomatTimeByPreference($dbTime,$timeZone,$timeFormat,$agentTimeZone,$agentTimeFormat);
  483. $currentDateTime = new \DateTime('now');
  484. if($this->getLastReply($ticket['id'])) {
  485. $lastRepliedTime =
  486. $this->time2string($currentDateTime->getTimeStamp() - $this->getLastReply($ticket['id'])['createdAt']->getTimeStamp());
  487. } else {
  488. $lastRepliedTime =
  489. $this->time2string($currentDateTime->getTimeStamp() - $ticket['createdAt']->getTimeStamp());
  490. }
  491. $ticketResponse = [
  492. 'id' => $ticket['id'],
  493. 'subject' => $ticket['subject'],
  494. 'isStarred' => $ticket['isStarred'],
  495. 'isAgentView' => $ticket['isAgentViewed'],
  496. 'isTrashed' => $ticket['isTrashed'],
  497. 'source' => $ticket['source'],
  498. 'group' => $ticketDetails['groupName'],
  499. 'team' => $ticketDetails['teamName'],
  500. 'priority' => $ticket['priority'],
  501. 'type' => $ticketDetails['typeName'],
  502. 'timestamp' => $formattedTime['dateTimeZone'],
  503. 'formatedCreatedAt' => $formattedTime['dateTimeZone']->format($formattedTime['timeFormatString']),
  504. 'totalThreads' => $totalTicketReplies,
  505. 'agent' => null,
  506. 'customer' => null,
  507. 'hasAttachments' => $ticketHasAttachments,
  508. 'lastReplyTime' => $lastRepliedTime
  509. ];
  510. if (!empty($ticketDetails['agentId'])) {
  511. $ticketResponse['agent'] = [
  512. 'id' => $ticketDetails['agentId'],
  513. 'name' => $ticketDetails['agentName'],
  514. 'smallThumbnail' => $ticketDetails['smallThumbnail'],
  515. ];
  516. }
  517. if (!empty($ticketDetails['customerId'])) {
  518. $ticketResponse['customer'] = [
  519. 'id' => $ticketDetails['customerId'],
  520. 'name' => $ticketDetails['customerName'],
  521. 'email' => $ticketDetails['customerEmail'],
  522. 'smallThumbnail' => $ticketDetails['customersmallThumbnail'],
  523. ];
  524. }
  525. array_push($ticketCollection, $ticketResponse);
  526. }
  527. return [
  528. 'tickets' => $ticketCollection,
  529. 'pagination' => $paginationData,
  530. 'tabs' => $ticketTabs,
  531. 'labels' => [
  532. 'predefind' => $this->getPredefindLabelDetails($activeUser, $supportGroupReference, $supportTeamReference, $params),
  533. 'custom' => $this->getCustomLabelDetails($this->container),
  534. ],
  535. ];
  536. }
  537. // Convert Timestamp to day/hour/min
  538. Public function time2string($time) {
  539. $d = floor($time/86400);
  540. $_d = ($d < 10 ? '0' : '').$d;
  541. $h = floor(($time-$d*86400)/3600);
  542. $_h = ($h < 10 ? '0' : '').$h;
  543. $m = floor(($time-($d*86400+$h*3600))/60);
  544. $_m = ($m < 10 ? '0' : '').$m;
  545. $s = $time-($d*86400+$h*3600+$m*60);
  546. $_s = ($s < 10 ? '0' : '').$s;
  547. $time_str = "0 minutes";
  548. if($_d != 00)
  549. $time_str = $_d." ".'days';
  550. elseif($_h != 00)
  551. $time_str = $_h." ".'hours';
  552. elseif($_m != 00)
  553. $time_str = $_m." ".'minutes';
  554. return $time_str." "."ago";
  555. }
  556. public function getPredefindLabelDetails(User $currentUser, array $supportGroupIds = [], array $supportTeamIds = [], array $params = [])
  557. {
  558. $data = array();
  559. $queryBuilder = $this->entityManager->createQueryBuilder();
  560. $ticketRepository = $this->entityManager->getRepository(Ticket::class);
  561. $queryBuilder->select('COUNT(DISTINCT ticket.id) as ticketCount')->from(Ticket::class, 'ticket');
  562. // // applyFilter according to permission
  563. $queryBuilder->where('ticket.isTrashed != 1');
  564. $userInstance = $currentUser->getAgentInstance();
  565. if (!empty($userInstance) && 'ROLE_AGENT' == $userInstance->getSupportRole()->getCode()
  566. && $userInstance->getTicketAccesslevel() != 1) {
  567. $supportGroupIds = implode(',', $supportGroupIds);
  568. $supportTeamIds = implode(',', $supportTeamIds);
  569. if ($userInstance->getTicketAccesslevel() == 4) {
  570. $queryBuilder->andwhere('ticket.agent = ' . $currentUser->getId());
  571. } elseif ($userInstance->getTicketAccesslevel() == 2) {
  572. $query = '';
  573. if ($supportGroupIds){
  574. $query .= ' OR supportGroup.id IN('.$supportGroupIds.') ';
  575. }
  576. if ($supportTeamIds) {
  577. $query .= ' OR supportTeam.id IN('.$supportTeamIds.') ';
  578. }
  579. $queryBuilder->leftJoin('ticket.supportGroup', 'supportGroup')
  580. ->leftJoin('ticket.supportTeam', 'supportTeam')
  581. ->andwhere('( ticket.agent = ' . $currentUser->getId().$query.')');
  582. } elseif ($userInstance->getTicketAccesslevel() == 3) {
  583. $query = '';
  584. if ($supportTeamIds) {
  585. $query .= ' OR supportTeam.id IN('.$supportTeamIds.') ';
  586. }
  587. $queryBuilder->leftJoin('ticket.supportGroup', 'supportGroup')
  588. ->leftJoin('ticket.supportTeam', 'supportTeam')
  589. ->andwhere('( ticket.agent = ' . $currentUser->getId().$query. ')');
  590. }
  591. }
  592. // for all tickets count
  593. $data['all'] = $queryBuilder->getQuery()->getSingleScalarResult();
  594. // for new tickets count
  595. $newQb = clone $queryBuilder;
  596. $newQb->andwhere('ticket.isNew = 1');
  597. $data['new'] = $newQb->getQuery()->getSingleScalarResult();
  598. // for unassigned tickets count
  599. $unassignedQb = clone $queryBuilder;
  600. $unassignedQb->andwhere("ticket.agent is NULL");
  601. $data['unassigned'] = $unassignedQb->getQuery()->getSingleScalarResult();
  602. // for unanswered ticket count
  603. $unansweredQb = clone $queryBuilder;
  604. $unansweredQb->andwhere('ticket.isReplied = 0');
  605. $data['notreplied'] = $unansweredQb->getQuery()->getSingleScalarResult();
  606. // for my tickets count
  607. $mineQb = clone $queryBuilder;
  608. $mineQb->andWhere("ticket.agent = :agentId")
  609. ->setParameter('agentId', $currentUser->getId());
  610. $data['mine'] = $mineQb->getQuery()->getSingleScalarResult();
  611. // for starred tickets count
  612. $starredQb = clone $queryBuilder;
  613. $starredQb->andwhere('ticket.isStarred = 1');
  614. $data['starred'] = $starredQb->getQuery()->getSingleScalarResult();
  615. // for trashed tickets count
  616. $trashedQb = clone $queryBuilder;
  617. $trashedQb->where('ticket.isTrashed = 1');
  618. if ($currentUser->getRoles()[0] != 'ROLE_SUPER_ADMIN' && $userInstance->getTicketAccesslevel() != 1) {
  619. $trashedQb->andwhere('ticket.agent = ' . $currentUser->getId());
  620. }
  621. $data['trashed'] = $trashedQb->getQuery()->getSingleScalarResult();
  622. return $data;
  623. }
  624. public function paginateMembersTicketThreadCollection(Ticket $ticket, Request $request)
  625. {
  626. $params = $request->query->all();
  627. $entityManager = $this->entityManager;
  628. $activeUser = $this->container->get('user.service')->getSessionUser();
  629. $activeUserTimeZone = $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'Knowledgebase']);
  630. $agentTimeZone = !empty($activeUser->getTimezone()) ? $activeUser->getTimezone() : $activeUserTimeZone->getTimezone();
  631. $agentTimeFormat = !empty($activeUser->getTimeformat()) ? $activeUser->getTimeformat() : $activeUserTimeZone->getTimeformat();
  632. $threadRepository = $entityManager->getRepository(Thread::class);
  633. $uvdeskFileSystemService = $this->container->get('uvdesk.core.file_system.service');
  634. // Get base query
  635. $enableLockedThreads = $this->container->get('user.service')->isAccessAuthorized('ROLE_AGENT_MANAGE_LOCK_AND_UNLOCK_THREAD');
  636. $baseQuery = $threadRepository->prepareBasePaginationRecentThreadsQuery($ticket, $params, $enableLockedThreads);
  637. // Apply Pagination
  638. $paginationItemsQuery = clone $baseQuery;
  639. $totalPaginationItems = $paginationItemsQuery->select('COUNT(DISTINCT thread.id)')->getQuery()->getSingleScalarResult();
  640. $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  641. $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $threadRepository::DEFAULT_PAGINATION_LIMIT;
  642. $paginationOptions = ['distinct' => true];
  643. $paginationQuery = $baseQuery->getQuery()->setHydrationMode(Query::HYDRATE_ARRAY)->setHint('knp_paginator.count', (int) $totalPaginationItems);
  644. $pagination = $this->container->get('knp_paginator')->paginate($paginationQuery, $pageNumber, $itemsLimit, $paginationOptions);
  645. // Process Pagination Response
  646. $threadCollection = [];
  647. $paginationParams = $pagination->getParams();
  648. $paginationData = $pagination->getPaginationData();
  649. $website = $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'helpdesk']);
  650. $timeZone = $website->getTimezone();
  651. $timeFormat = $website->getTimeformat();
  652. if (!empty($params['threadRequestedId'])) {
  653. $requestedThreadCollection = $baseQuery
  654. ->andWhere('thread.id >= :threadRequestedId')->setParameter('threadRequestedId', (int) $params['threadRequestedId'])
  655. ->getQuery()->getArrayResult();
  656. $totalRequestedThreads = count($requestedThreadCollection);
  657. $paginationData['current'] = ceil($totalRequestedThreads / $threadRepository::DEFAULT_PAGINATION_LIMIT);
  658. if ($paginationData['current'] > 1) {
  659. $paginationData['firstItemNumber'] = 1;
  660. $paginationData['lastItemNumber'] = $totalRequestedThreads;
  661. $paginationData['next'] = ceil(($totalRequestedThreads + 1) / $threadRepository::DEFAULT_PAGINATION_LIMIT);
  662. }
  663. }
  664. $paginationParams['page'] = 'replacePage';
  665. $paginationData['url'] = '#' . $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  666. foreach ($pagination->getItems() as $threadDetails) {
  667. $dbTime = $threadDetails['createdAt'];
  668. $formattedTime = $this->fomatTimeByPreference($dbTime,$timeZone,$timeFormat,$agentTimeZone,$agentTimeFormat);
  669. $threadResponse = [
  670. 'id' => $threadDetails['id'],
  671. 'user' => null,
  672. 'fullname' => null,
  673. 'reply' => html_entity_decode($threadDetails['message']),
  674. 'source' => $threadDetails['source'],
  675. 'threadType' => $threadDetails['threadType'],
  676. 'userType' => $threadDetails['createdBy'],
  677. 'timestamp' => $formattedTime['dateTimeZone'],
  678. 'formatedCreatedAt' => $formattedTime['dateTimeZone']->format($formattedTime['timeFormatString']),
  679. 'bookmark' => $threadDetails['isBookmarked'],
  680. 'isLocked' => $threadDetails['isLocked'],
  681. 'replyTo' => $threadDetails['replyTo'],
  682. 'cc' => $threadDetails['cc'],
  683. 'bcc' => $threadDetails['bcc'],
  684. 'attachments' => $threadDetails['attachments'],
  685. ];
  686. if (!empty($threadDetails['user'])) {
  687. $threadResponse['fullname'] = trim($threadDetails['user']['firstName'] . ' ' . $threadDetails['user']['lastName']);
  688. $threadResponse['user'] = [
  689. 'id' => $threadDetails['user']['id'],
  690. 'smallThumbnail' => $threadDetails['user']['userInstance'][0]['profileImagePath'],
  691. 'name' => $threadResponse['fullname'],
  692. ];
  693. }
  694. if (!empty($threadResponse['attachments'])) {
  695. $threadResponse['attachments'] = array_map(function ($attachment) use ($entityManager, $uvdeskFileSystemService) {
  696. $attachmentReferenceObject = $entityManager->getReference(Attachment::class, $attachment['id']);
  697. return $uvdeskFileSystemService->getFileTypeAssociations($attachmentReferenceObject);
  698. }, $threadResponse['attachments']);
  699. }
  700. array_push($threadCollection, $threadResponse);
  701. }
  702. return [
  703. 'threads' => $threadCollection,
  704. 'pagination' => $paginationData,
  705. ];
  706. }
  707. public function massXhrUpdate(Request $request)
  708. {
  709. $params = $request->request->get('data');
  710. foreach ($params['ids'] as $ticketId) {
  711. $ticket = $this->entityManager->getRepository(Ticket::class)->find($ticketId);
  712. if (false == $this->isTicketAccessGranted($ticket)) {
  713. throw new \Exception('Access Denied', 403);
  714. }
  715. if (empty($ticket)) {
  716. continue;
  717. }
  718. switch ($params['actionType']) {
  719. case 'trashed':
  720. if (false == $ticket->getIsTrashed()) {
  721. $ticket->setIsTrashed(true);
  722. $this->entityManager->persist($ticket);
  723. }
  724. // Trigger ticket delete event
  725. $event = new CoreWorkflowEvents\Ticket\Delete();
  726. $event
  727. ->setTicket($ticket)
  728. ;
  729. $this->container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  730. break;
  731. case 'delete':
  732. $threads = $ticket->getThreads();
  733. $fileService = new Filesystem();
  734. if (count($threads) > 0) {
  735. foreach($threads as $thread) {
  736. if (!empty($thread)) {
  737. $fileService->remove($this->container->getParameter('kernel.project_dir').'/public/assets/threads/'.$thread->getId());
  738. }
  739. }
  740. }
  741. $this->entityManager->remove($ticket);
  742. break;
  743. case 'restored':
  744. if (true == $ticket->getIsTrashed()) {
  745. $ticket->setIsTrashed(false);
  746. $this->entityManager->persist($ticket);
  747. }
  748. break;
  749. case 'agent':
  750. if ($ticket->getAgent() == null || $ticket->getAgent() && $ticket->getAgent()->getId() != $params['targetId']) {
  751. $agent = $this->entityManager->getRepository(User::class)->find($params['targetId']);
  752. $ticket->setAgent($agent);
  753. $this->entityManager->persist($ticket);
  754. // Trigger Agent Assign event
  755. $event = new CoreWorkflowEvents\Ticket\Agent();
  756. $event
  757. ->setTicket($ticket)
  758. ;
  759. $this->container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  760. }
  761. break;
  762. case 'status':
  763. if ($ticket->getStatus() == null || $ticket->getStatus() && $ticket->getStatus()->getId() != $params['targetId']) {
  764. $status = $this->entityManager->getRepository(TicketStatus::class)->findOneById($params['targetId']);
  765. $ticket->setStatus($status);
  766. $this->entityManager->persist($ticket);
  767. // Trigger ticket status event
  768. $event = new CoreWorkflowEvents\Ticket\Status();
  769. $event
  770. ->setTicket($ticket)
  771. ;
  772. $this->container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  773. }
  774. break;
  775. case 'type':
  776. if ($ticket->getType() == null || $ticket->getType() && $ticket->getType()->getId() != $params['targetId']) {
  777. $type = $this->entityManager->getRepository(TicketType::class)->findOneById($params['targetId']);
  778. $ticket->setType($type);
  779. $this->entityManager->persist($ticket);
  780. // Trigger ticket type event
  781. $event = new CoreWorkflowEvents\Ticket\Type();
  782. $event
  783. ->setTicket($ticket)
  784. ;
  785. $this->container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  786. }
  787. break;
  788. case 'group':
  789. if ($ticket->getSupportGroup() == null || $ticket->getSupportGroup() && $ticket->getSupportGroup()->getId() != $params['targetId']) {
  790. $group = $this->entityManager->getRepository(SupportGroup::class)->find($params['targetId']);
  791. $ticket->setSupportGroup($group);
  792. $this->entityManager->persist($ticket);
  793. // Trigger Support group event
  794. $event = new CoreWorkflowEvents\Ticket\Group();
  795. $event
  796. ->setTicket($ticket)
  797. ;
  798. $this->container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  799. }
  800. break;
  801. case 'team':
  802. if ($ticket->getSupportTeam() == null || $ticket->getSupportTeam() && $ticket->getSupportTeam()->getId() != $params['targetId']){
  803. $team = $this->entityManager->getRepository(SupportTeam::class)->find($params['targetId']);
  804. $ticket->setSupportTeam($team);
  805. $this->entityManager->persist($ticket);
  806. // Trigger team event
  807. $event = new CoreWorkflowEvents\Ticket\Team();
  808. $event
  809. ->setTicket($ticket)
  810. ;
  811. $this->container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  812. }
  813. break;
  814. case 'priority':
  815. if ($ticket->getPriority() == null || $ticket->getPriority() && $ticket->getPriority()->getId() != $params['targetId']) {
  816. $priority = $this->entityManager->getRepository(TicketPriority::class)->find($params['targetId']);
  817. $ticket->setPriority($priority);
  818. $this->entityManager->persist($ticket);
  819. // Trigger ticket Priority event
  820. $event = new CoreWorkflowEvents\Ticket\Priority();
  821. $event
  822. ->setTicket($ticket)
  823. ;
  824. $this->container->get('event_dispatcher')->dispatch($event, 'uvdesk.automation.workflow.execute');
  825. }
  826. break;
  827. case 'label':
  828. $label = $this->entityManager->getRepository(SupportLabel::class)->find($params['targetId']);
  829. if ($label && !$this->entityManager->getRepository(Ticket::class)->isLabelAlreadyAdded($ticket, $label)) {
  830. $ticket->addSupportLabel($label);
  831. }
  832. $this->entityManager->persist($ticket);
  833. break;
  834. default:
  835. break;
  836. }
  837. }
  838. $this->entityManager->flush();
  839. return [
  840. 'alertClass' => 'success',
  841. 'alertMessage' => $this->trans('Tickets have been updated successfully'),
  842. ];
  843. }
  844. public function getNotePlaceholderValues($ticket, $type = "customer")
  845. {
  846. $variables = array();
  847. $variables['ticket.id'] = $ticket->getId();
  848. $variables['ticket.subject'] = $ticket->getSubject();
  849. $variables['ticket.status'] = $ticket->getStatus()->getCode();
  850. $variables['ticket.priority'] = $ticket->getPriority()->getCode();
  851. if($ticket->getSupportGroup())
  852. $variables['ticket.group'] = $ticket->getSupportGroup()->getName();
  853. else
  854. $variables['ticket.group'] = '';
  855. $variables['ticket.team'] = ($ticket->getSupportTeam() ? $ticket->getSupportTeam()->getName() : '');
  856. $customer = $this->container->get('user.service')->getCustomerPartialDetailById($ticket->getCustomer()->getId());
  857. $variables['ticket.customerName'] = $customer['name'];
  858. $userService = $this->container->get('user.service');
  859. $variables['ticket.agentName'] = '';
  860. $variables['ticket.agentEmail'] = '';
  861. if ($ticket->getAgent()) {
  862. $agent = $this->container->get('user.service')->getAgentDetailById($ticket->getAgent()->getId());
  863. if($agent) {
  864. $variables['ticket.agentName'] = $agent['name'];
  865. $variables['ticket.agentEmail'] = $agent['email'];
  866. }
  867. }
  868. $router = $this->container->get('router');
  869. if ($type == 'customer') {
  870. $ticketListURL = $router->generate('helpdesk_member_ticket_collection', [
  871. 'id' => $ticket->getId(),
  872. ], UrlGeneratorInterface::ABSOLUTE_URL);
  873. } else {
  874. $ticketListURL = $router->generate('helpdesk_customer_ticket_collection', [
  875. 'id' => $ticket->getId(),
  876. ], UrlGeneratorInterface::ABSOLUTE_URL);
  877. }
  878. $variables['ticket.link'] = sprintf("<a href='%s'>#%s</a>", $ticketListURL, $ticket->getId());
  879. return $variables;
  880. }
  881. public function paginateMembersTicketTypeCollection(Request $request)
  882. {
  883. // Get base query
  884. $params = $request->query->all();
  885. $ticketRepository = $this->entityManager->getRepository(Ticket::class);
  886. $paginationQuery = $ticketRepository->prepareBasePaginationTicketTypesQuery($params);
  887. // Apply Pagination
  888. $paginationOptions = ['distinct' => true];
  889. $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  890. $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $ticketRepository::DEFAULT_PAGINATION_LIMIT;
  891. $pagination = $this->container->get('knp_paginator')->paginate($paginationQuery, $pageNumber, $itemsLimit, $paginationOptions);
  892. // Process Pagination Response
  893. $paginationParams = $pagination->getParams();
  894. $paginationData = $pagination->getPaginationData();
  895. $paginationParams['page'] = 'replacePage';
  896. $paginationData['url'] = '#' . $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  897. return [
  898. 'types' => array_map(function ($ticketType) {
  899. return [
  900. 'id' => $ticketType->getId(),
  901. 'code' => strtoupper($ticketType->getCode()),
  902. 'description' => $ticketType->getDescription(),
  903. 'isActive' => $ticketType->getIsActive(),
  904. ];
  905. }, $pagination->getItems()),
  906. 'pagination_data' => $paginationData,
  907. ];
  908. }
  909. public function paginateMembersTagCollection(Request $request)
  910. {
  911. // Get base query
  912. $params = $request->query->all();
  913. $ticketRepository = $this->entityManager->getRepository(Ticket::class);
  914. $baseQuery = $ticketRepository->prepareBasePaginationTagsQuery($params);
  915. // Apply Pagination
  916. $paginationResultsQuery = clone $baseQuery;
  917. $paginationResultsQuery->select('COUNT(supportTag.id)');
  918. $paginationQuery = $baseQuery->getQuery()->setHydrationMode(Query::HYDRATE_ARRAY)->setHint('knp_paginator.count', count($paginationResultsQuery->getQuery()->getResult()));
  919. $paginationOptions = ['distinct' => true];
  920. $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  921. $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $ticketRepository::DEFAULT_PAGINATION_LIMIT;
  922. $pagination = $this->container->get('knp_paginator')->paginate($paginationQuery, $pageNumber, $itemsLimit, $paginationOptions);
  923. // Process Pagination Response
  924. $paginationParams = $pagination->getParams();
  925. $paginationData = $pagination->getPaginationData();
  926. $paginationParams['page'] = 'replacePage';
  927. $paginationData['url'] = '#' . $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  928. if (in_array('UVDeskSupportCenterBundle', array_keys($this->container->getParameter('kernel.bundles')))) {
  929. $articleRepository = $this->entityManager->getRepository(Article::class);
  930. return [
  931. 'tags' => array_map(function ($supportTag) use ($articleRepository) {
  932. return [
  933. 'id' => $supportTag['id'],
  934. 'name' => $supportTag['name'],
  935. 'ticketCount' => $supportTag['totalTickets'],
  936. 'articleCount' => $articleRepository->getTotalArticlesBySupportTag($supportTag['id']),
  937. ];
  938. }, $pagination->getItems()),
  939. 'pagination_data' => $paginationData,
  940. ];
  941. } else {
  942. return [
  943. 'tags' => array_map(function ($supportTag) {
  944. return [
  945. 'id' => $supportTag['id'],
  946. 'name' => $supportTag['name'],
  947. 'ticketCount' => $supportTag['totalTickets'],
  948. ];
  949. }, $pagination->getItems()),
  950. 'pagination_data' => $paginationData,
  951. ];
  952. }
  953. }
  954. public function getTicketInitialThreadDetails(Ticket $ticket)
  955. {
  956. $initialThread = $this->entityManager->getRepository(Thread::class)->findOneBy([
  957. 'ticket' => $ticket,
  958. 'threadType' => 'create',
  959. ]);
  960. if (!empty($initialThread)) {
  961. $author = $initialThread->getUser();
  962. $authorInstance = 'agent' == $initialThread->getCreatedBy() ? $author->getAgentInstance() : $author->getCustomerInstance();
  963. $threadDetails = [
  964. 'id' => $initialThread->getId(),
  965. 'source' => $initialThread->getSource(),
  966. 'messageId' => $initialThread->getMessageId(),
  967. 'threadType' => $initialThread->getThreadType(),
  968. 'createdBy' => $initialThread->getCreatedBy(),
  969. 'message' => html_entity_decode($initialThread->getMessage()),
  970. 'attachments' => $initialThread->getAttachments(),
  971. 'timestamp' => $initialThread->getCreatedAt()->getTimestamp(),
  972. 'createdAt' => $initialThread->getCreatedAt()->format('d-m-Y h:ia'),
  973. 'user' => $authorInstance->getPartialDetails(),
  974. 'cc' => is_array($initialThread->getCc()) ? implode(', ', $initialThread->getCc()) : '',
  975. ];
  976. $attachments = $threadDetails['attachments']->getValues();
  977. if (!empty($attachments)) {
  978. $uvdeskFileSystemService = $this->container->get('uvdesk.core.file_system.service');
  979. $threadDetails['attachments'] = array_map(function ($attachment) use ($uvdeskFileSystemService) {
  980. return $uvdeskFileSystemService->getFileTypeAssociations($attachment);
  981. }, $attachments);
  982. }
  983. }
  984. return $threadDetails ?? null;
  985. }
  986. public function getCreateReply($ticketId, $firewall = 'member')
  987. {
  988. $qb = $this->entityManager->createQueryBuilder();
  989. $qb->select("th,a,u.id as userId")->from(Thread::class, 'th')
  990. ->leftJoin('th.ticket','t')
  991. ->leftJoin('th.attachments', 'a')
  992. ->leftJoin('th.user','u')
  993. ->andWhere('t.id = :ticketId')
  994. ->andWhere('th.threadType = :threadType')
  995. ->setParameter('threadType','create')
  996. ->setParameter('ticketId',$ticketId)
  997. ->orderBy('th.id', 'DESC')
  998. ->getMaxResults(1);
  999. $threadResponse = $qb->getQuery()->getArrayResult();
  1000. if((!empty($threadResponse[0][0]))) {
  1001. $threadDetails = $threadResponse[0][0];
  1002. $userService = $this->container->get('user.service');
  1003. if ($threadDetails['createdBy'] == 'agent') {
  1004. $threadDetails['user'] = $userService->getAgentDetailById($threadResponse[0]['userId']);
  1005. } else {
  1006. $threadDetails['user'] = $userService->getCustomerPartialDetailById($threadResponse[0]['userId']);
  1007. }
  1008. $threadDetails['reply'] = html_entity_decode($threadDetails['message']);
  1009. $threadDetails['formatedCreatedAt'] = $this->timeZoneConverter($threadDetails['createdAt']);
  1010. $threadDetails['timestamp'] = $userService->convertToDatetimeTimezoneTimestamp($threadDetails['createdAt']);
  1011. if (!empty($threadDetails['attachments'])) {
  1012. $entityManager = $this->entityManager;
  1013. $uvdeskFileSystemService = $this->container->get('uvdesk.core.file_system.service');
  1014. $threadDetails['attachments'] = array_map(function ($attachment) use ($entityManager, $uvdeskFileSystemService, $firewall) {
  1015. $attachmentReferenceObject = $entityManager->getReference(Attachment::class, $attachment['id']);
  1016. return $uvdeskFileSystemService->getFileTypeAssociations($attachmentReferenceObject, $firewall);
  1017. }, $threadDetails['attachments']);
  1018. }
  1019. }
  1020. return $threadDetails ?? null;
  1021. }
  1022. public function hasAttachments($ticketId) {
  1023. $qb = $this->entityManager->createQueryBuilder();
  1024. $qb->select("DISTINCT COUNT(a.id) as attachmentCount")->from(Thread::class, 'th')
  1025. ->leftJoin('th.ticket','t')
  1026. ->leftJoin('th.attachments','a')
  1027. ->andWhere('t.id = :ticketId')
  1028. ->setParameter('ticketId',$ticketId);
  1029. return intval($qb->getQuery()->getSingleScalarResult());
  1030. }
  1031. public function getAgentDraftReply()
  1032. {
  1033. $signature = $this->getUser()->getAgentInstance()->getSignature();
  1034. return str_replace( "\n", '<br/>', $signature);
  1035. }
  1036. public function trans($text)
  1037. {
  1038. return $this->container->get('translator')->trans($text);
  1039. }
  1040. public function getAllSources()
  1041. {
  1042. $sources = ['email' => 'Email', 'website' => 'Website'];
  1043. return $sources;
  1044. }
  1045. public function getCustomLabelDetails($container)
  1046. {
  1047. $currentUser = $container->get('user.service')->getCurrentUser();
  1048. $qb = $this->entityManager->createQueryBuilder();
  1049. $qb->select('COUNT(DISTINCT t) as ticketCount,sl.id')->from(Ticket::class, 't')
  1050. ->leftJoin('t.supportLabels','sl')
  1051. ->andwhere('sl.user = :userId')
  1052. ->setParameter('userId', $currentUser->getId())
  1053. ->groupBy('sl.id');
  1054. $ticketCountResult = $qb->getQuery()->getResult();
  1055. $data = array();
  1056. $qb = $this->entityManager->createQueryBuilder();
  1057. $qb->select('sl.id,sl.name,sl.colorCode')->from(SupportLabel::class, 'sl')
  1058. ->andwhere('sl.user = :userId')
  1059. ->setParameter('userId', $currentUser->getId());
  1060. $labels = $qb->getQuery()->getResult();
  1061. foreach ($labels as $key => $label) {
  1062. $labels[$key]['count'] = 0;
  1063. foreach ($ticketCountResult as $ticketCount) {
  1064. if(($label['id'] == $ticketCount['id']))
  1065. $labels[$key]['count'] = $ticketCount['ticketCount'] ?: 0;
  1066. }
  1067. }
  1068. return $labels;
  1069. }
  1070. public function getLabels($request = null)
  1071. {
  1072. static $labels;
  1073. if (null !== $labels)
  1074. return $labels;
  1075. $qb = $this->entityManager->createQueryBuilder();
  1076. $qb->select('sl')->from(SupportLabel::class, 'sl')
  1077. ->andwhere('sl.user = :userId')
  1078. ->setParameter('userId', $this->getUser()->getId());
  1079. if($request) {
  1080. $qb->andwhere("sl.name LIKE :labelName");
  1081. $qb->setParameter('labelName', '%'.urldecode($request->query->get('query')).'%');
  1082. }
  1083. return $labels = $qb->getQuery()->getArrayResult();
  1084. }
  1085. public function getTicketCollaborators($ticketId)
  1086. {
  1087. $qb = $this->entityManager->createQueryBuilder();
  1088. $qb->select("DISTINCT c.id, c.email, CONCAT(c.firstName,' ', c.lastName) AS name, userInstance.profileImagePath, userInstance.profileImagePath as smallThumbnail")->from(Ticket::class, 't')
  1089. ->leftJoin('t.collaborators', 'c')
  1090. ->leftJoin('c.userInstance', 'userInstance')
  1091. ->andwhere('t.id = :ticketId')
  1092. ->andwhere('userInstance.supportRole = :roles')
  1093. ->setParameter('ticketId', $ticketId)
  1094. ->setParameter('roles', 4)
  1095. ->orderBy('name','ASC');
  1096. return $qb->getQuery()->getArrayResult();
  1097. }
  1098. public function getTicketTagsById($ticketId)
  1099. {
  1100. $qb = $this->entityManager->createQueryBuilder();
  1101. $qb->select('tg')->from(Tag::class, 'tg')
  1102. ->leftJoin('tg.tickets' ,'t')
  1103. ->andwhere('t.id = :ticketId')
  1104. ->setParameter('ticketId', $ticketId);
  1105. return $qb->getQuery()->getArrayResult();
  1106. }
  1107. public function getTicketLabels($ticketId)
  1108. {
  1109. $qb = $this->entityManager->createQueryBuilder();
  1110. $qb->select('DISTINCT sl.id,sl.name,sl.colorCode')->from(Ticket::class, 't')
  1111. ->leftJoin('t.supportLabels','sl')
  1112. ->leftJoin('sl.user','slu')
  1113. ->andWhere('slu.id = :userId')
  1114. ->andWhere('t.id = :ticketId')
  1115. ->setParameter('userId', $this->getUser()->getId())
  1116. ->setParameter('ticketId', $ticketId);
  1117. $result = $qb->getQuery()->getResult();
  1118. return $result ? $result : [];
  1119. }
  1120. public function getUserLabels()
  1121. {
  1122. $qb = $this->entityManager->createQueryBuilder();
  1123. $qb->select('sl')->from(SupportLabel::class, 'sl')
  1124. ->leftJoin('sl.user','slu')
  1125. ->andWhere('slu.id = :userId')
  1126. ->setParameter('userId', $this->getUser()->getId());
  1127. $result = $qb->getQuery()->getResult();
  1128. return $result ? $result : [];
  1129. }
  1130. public function getTicketLabelsAll($ticketId)
  1131. {
  1132. $qb = $this->entityManager->createQueryBuilder();
  1133. $qb->select('DISTINCT sl.id,sl.name,sl.colorCode')->from(Ticket::class, 't')
  1134. ->leftJoin('t.supportLabels','sl')
  1135. ->andWhere('t.id = :ticketId')
  1136. ->setParameter('ticketId', $ticketId);
  1137. $result = $qb->getQuery()->getResult();
  1138. return $result ? $result : [];
  1139. }
  1140. public function getManualWorkflow()
  1141. {
  1142. $preparedResponseIds = [];
  1143. $groupIds = [];
  1144. $teamIds = [];
  1145. $userId = $this->container->get('user.service')->getCurrentUser()->getAgentInstance()->getId();
  1146. $preparedResponseRepo = $this->entityManager->getRepository(PreparedResponses::class)->findAll();
  1147. foreach ($preparedResponseRepo as $pr) {
  1148. if ($userId == $pr->getUser()->getId()) {
  1149. //Save the ids of the saved reply.
  1150. array_push($preparedResponseIds, (int)$pr->getId());
  1151. }
  1152. }
  1153. // Get the ids of the Group(s) the current user is associated with.
  1154. $query = "select * from uv_user_support_groups where userInstanceId =".$userId;
  1155. $connection = $this->entityManager->getConnection();
  1156. $stmt = $connection->prepare($query);
  1157. $stmt->execute();
  1158. $result = $stmt->fetchAll();
  1159. foreach ($result as $row) {
  1160. array_push($groupIds, $row['supportGroupId']);
  1161. }
  1162. // Get all the saved reply's ids that is associated with the user's group(s).
  1163. $query = "select * from uv_prepared_response_support_groups";
  1164. $stmt = $connection->prepare($query);
  1165. $stmt->execute();
  1166. $result = $stmt->fetchAll();
  1167. foreach ($result as $row) {
  1168. if (in_array($row['group_id'], $groupIds)) {
  1169. array_push($preparedResponseIds, (int) $row['savedReply_id']);
  1170. }
  1171. }
  1172. // Get the ids of the Team(s) the current user is associated with.
  1173. $query = "select * from uv_user_support_teams";
  1174. $connection = $this->entityManager->getConnection();
  1175. $stmt = $connection->prepare($query);
  1176. $stmt->execute();
  1177. $result = $stmt->fetchAll();
  1178. foreach($result as $row) {
  1179. if ($row['userInstanceId'] == $userId) {
  1180. array_push($teamIds, $row['supportTeamId']);
  1181. }
  1182. }
  1183. $query = "select * from uv_prepared_response_support_teams";
  1184. $stmt = $connection->prepare($query);
  1185. $stmt->execute();
  1186. $result = $stmt->fetchAll();
  1187. foreach ($result as $row) {
  1188. if (in_array($row['subgroup_id'], $teamIds)) {
  1189. array_push($preparedResponseIds, (int)$row['savedReply_id']);
  1190. }
  1191. }
  1192. $qb = $this->entityManager->createQueryBuilder();
  1193. $qb->select('DISTINCT mw')
  1194. ->from(PreparedResponses::class, 'mw')
  1195. ->where('mw.status = 1')
  1196. ->andWhere('mw.id IN (:ids)')
  1197. ->setParameter('ids', $preparedResponseIds);
  1198. return $qb->getQuery()->getResult();
  1199. }
  1200. public function getSavedReplies()
  1201. {
  1202. $savedReplyIds = [];
  1203. $groupIds = [];
  1204. $teamIds = [];
  1205. $userId = $this->container->get('user.service')->getCurrentUser()->getAgentInstance()->getId();
  1206. $savedReplyRepo = $this->entityManager->getRepository(SavedReplies::class)->findAll();
  1207. foreach ($savedReplyRepo as $sr) {
  1208. if ($userId == $sr->getUser()->getId()) {
  1209. //Save the ids of the saved reply.
  1210. array_push($savedReplyIds, (int)$sr->getId());
  1211. }
  1212. }
  1213. // Get the ids of the Group(s) the current user is associated with.
  1214. $query = "select * from uv_user_support_groups where userInstanceId =".$userId;
  1215. $connection = $this->entityManager->getConnection();
  1216. $stmt = $connection->prepare($query);
  1217. $stmt->execute();
  1218. $result = $stmt->fetchAll();
  1219. foreach ($result as $row) {
  1220. array_push($groupIds, $row['supportGroupId']);
  1221. }
  1222. // Get all the saved reply's ids that is associated with the user's group(s).
  1223. $query = "select * from uv_saved_replies_groups";
  1224. $stmt = $connection->prepare($query);
  1225. $stmt->execute();
  1226. $result = $stmt->fetchAll();
  1227. foreach ($result as $row) {
  1228. if (in_array($row['group_id'], $groupIds)) {
  1229. array_push($savedReplyIds, (int) $row['savedReply_id']);
  1230. }
  1231. }
  1232. // Get the ids of the Team(s) the current user is associated with.
  1233. $query = "select * from uv_user_support_teams";
  1234. $connection = $this->entityManager->getConnection();
  1235. $stmt = $connection->prepare($query);
  1236. $stmt->execute();
  1237. $result = $stmt->fetchAll();
  1238. foreach($result as $row) {
  1239. if ($row['userInstanceId'] == $userId) {
  1240. array_push($teamIds, $row['supportTeamId']);
  1241. }
  1242. }
  1243. $query = "select * from uv_saved_replies_teams";
  1244. $stmt = $connection->prepare($query);
  1245. $stmt->execute();
  1246. $result = $stmt->fetchAll();
  1247. foreach ($result as $row) {
  1248. if (in_array($row['subgroup_id'], $teamIds)) {
  1249. array_push($savedReplyIds, (int)$row['savedReply_id']);
  1250. }
  1251. }
  1252. $qb = $this->entityManager->createQueryBuilder();
  1253. $qb->select('DISTINCT sr')
  1254. ->from(SavedReplies::class, 'sr')
  1255. ->Where('sr.id IN (:ids)')
  1256. ->setParameter('ids', $savedReplyIds);
  1257. return $qb->getQuery()->getResult();
  1258. }
  1259. public function getPriorities()
  1260. {
  1261. static $priorities;
  1262. if (null !== $priorities)
  1263. return $priorities;
  1264. $qb = $this->entityManager->createQueryBuilder();
  1265. $qb->select('tp')->from(TicketPriority::class, 'tp');
  1266. return $priorities = $qb->getQuery()->getArrayResult();
  1267. }
  1268. public function getTicketLastThread($ticketId)
  1269. {
  1270. $qb = $this->entityManager->createQueryBuilder();
  1271. $qb->select("th")->from(Thread::class, 'th')
  1272. ->leftJoin('th.ticket','t')
  1273. ->andWhere('t.id = :ticketId')
  1274. ->setParameter('ticketId',$ticketId)
  1275. ->orderBy('th.id', 'DESC');
  1276. return $qb->getQuery()->setMaxResults(1)->getSingleResult();
  1277. }
  1278. public function getlastReplyAgentName($ticketId)
  1279. {
  1280. $qb = $this->entityManager->createQueryBuilder();
  1281. $qb->select("u.id,CONCAT(u.firstName,' ', u.lastName) AS name,u.firstName")->from(Thread::class, 'th')
  1282. ->leftJoin('th.ticket','t')
  1283. ->leftJoin('th.user', 'u')
  1284. ->leftJoin('u.userInstance', 'userInstance')
  1285. ->andwhere('userInstance.supportRole != :roles')
  1286. ->andWhere('t.id = :ticketId')
  1287. ->andWhere('th.threadType = :threadType')
  1288. ->setParameter('threadType','reply')
  1289. ->andWhere('th.createdBy = :createdBy')
  1290. ->setParameter('createdBy','agent')
  1291. ->setParameter('ticketId',$ticketId)
  1292. ->setParameter('roles', 4)
  1293. ->orderBy('th.id', 'DESC');
  1294. $result = $qb->getQuery()->setMaxResults(1)->getResult();
  1295. return $result ? $result[0] : null;
  1296. }
  1297. public function getLastReply($ticketId, $userType = null)
  1298. {
  1299. $queryBuilder = $this->entityManager->createQueryBuilder();
  1300. $queryBuilder->select("th, a, u.id as userId")
  1301. ->from(Thread::class, 'th')
  1302. ->leftJoin('th.ticket','t')
  1303. ->leftJoin('th.attachments', 'a')
  1304. ->leftJoin('th.user','u')
  1305. ->andWhere('t.id = :ticketId')
  1306. ->andWhere('th.threadType = :threadType')
  1307. ->setParameter('threadType','reply')
  1308. ->setParameter('ticketId',$ticketId)
  1309. ->orderBy('th.id', 'DESC')
  1310. ->getMaxResults(1);
  1311. if (!empty($userType)) {
  1312. $queryBuilder->andWhere('th.createdBy = :createdBy')->setParameter('createdBy', $userType);
  1313. }
  1314. $threadResponse = $queryBuilder->getQuery()->getArrayResult();
  1315. if (!empty($threadResponse[0][0])) {
  1316. $threadDetails = $threadResponse[0][0];
  1317. $userService = $this->container->get('user.service');
  1318. if ($threadDetails['createdBy'] == 'agent') {
  1319. $threadDetails['user'] = $userService->getAgentDetailById($threadResponse[0]['userId']);
  1320. } else {
  1321. $threadDetails['user'] = $userService->getCustomerPartialDetailById($threadResponse[0]['userId']);
  1322. }
  1323. $threadDetails['reply'] = html_entity_decode($threadDetails['message']);
  1324. $threadDetails['formatedCreatedAt'] = $this->timeZoneConverter($threadDetails['createdAt']);
  1325. $threadDetails['timestamp'] = $userService->convertToDatetimeTimezoneTimestamp($threadDetails['createdAt']);
  1326. if (!empty($threadDetails['attachments'])) {
  1327. $entityManager = $this->entityManager;
  1328. $uvdeskFileSystemService = $this->container->get('uvdesk.core.file_system.service');
  1329. $threadDetails['attachments'] = array_map(function ($attachment) use ($entityManager, $uvdeskFileSystemService) {
  1330. $attachmentReferenceObject = $this->entityManager->getReference(Attachment::class, $attachment['id']);
  1331. return $uvdeskFileSystemService->getFileTypeAssociations($attachmentReferenceObject);
  1332. }, $threadDetails['attachments']);
  1333. }
  1334. }
  1335. return $threadDetails ?? null;
  1336. }
  1337. public function getSavedReplyContent($savedReplyId, $ticketId)
  1338. {
  1339. $ticket = $this->entityManager->getRepository(Ticket::class)->find($ticketId);
  1340. $savedReply = $this->entityManager->getRepository(SavedReplies::class)->findOneById($savedReplyId);
  1341. $emailPlaceholders = $this->getSavedReplyPlaceholderValues($ticket, 'customer');
  1342. return $this->container->get('email.service')->processEmailContent($savedReply->getMessage(), $emailPlaceholders, true);
  1343. }
  1344. public function getSavedReplyPlaceholderValues($ticket, $type = "customer")
  1345. {
  1346. $variables = array();
  1347. $variables['ticket.id'] = $ticket->getId();
  1348. $variables['ticket.subject'] = $ticket->getSubject();
  1349. $variables['ticket.status'] = $ticket->getStatus()->getCode();
  1350. $variables['ticket.priority'] = $ticket->getPriority()->getCode();
  1351. if($ticket->getSupportGroup())
  1352. $variables['ticket.group'] = $ticket->getSupportGroup()->getName();
  1353. else
  1354. $variables['ticket.group'] = '';
  1355. $variables['ticket.team'] = ($ticket->getSupportTeam() ? $ticket->getSupportTeam()->getName() : '');
  1356. $customer = $this->container->get('user.service')->getCustomerPartialDetailById($ticket->getCustomer()->getId());
  1357. $variables['ticket.customerName'] = $customer['name'];
  1358. $variables['ticket.customerEmail'] = $customer['email'];
  1359. $userService = $this->container->get('user.service');
  1360. $variables['ticket.agentName'] = '';
  1361. $variables['ticket.agentEmail'] = '';
  1362. if ($ticket->getAgent()) {
  1363. $agent = $this->container->get('user.service')->getAgentDetailById($ticket->getAgent()->getId());
  1364. if($agent) {
  1365. $variables['ticket.agentName'] = $agent['name'];
  1366. $variables['ticket.agentEmail'] = $agent['email'];
  1367. }
  1368. }
  1369. $router = $this->container->get('router');
  1370. if ($type == 'customer') {
  1371. $ticketListURL = $router->generate('helpdesk_customer_ticket_collection', [
  1372. 'id' => $ticket->getId(),
  1373. ], UrlGeneratorInterface::ABSOLUTE_URL);
  1374. } else {
  1375. $ticketListURL = $router->generate('helpdesk_member_ticket_collection', [
  1376. 'id' => $ticket->getId(),
  1377. ], UrlGeneratorInterface::ABSOLUTE_URL);
  1378. }
  1379. $variables['ticket.link'] = sprintf("<a href='%s'>#%s</a>", $ticketListURL, $ticket->getId());
  1380. return $variables;
  1381. }
  1382. public function isEmailBlocked($email, $website)
  1383. {
  1384. $flag = false;
  1385. $email = strtolower($email);
  1386. $knowlegeBaseWebsite = $this->entityManager->getRepository(KnowledgebaseWebsite::class)->findOneBy(['website' => $website->getId(), 'isActive' => 1]);
  1387. $list = $this->container->get('user.service')->getWebsiteSpamDetails($knowlegeBaseWebsite);
  1388. // Blacklist
  1389. if (!empty($list['blackList']['email']) && in_array($email, $list['blackList']['email'])) {
  1390. // Emails
  1391. $flag = true;
  1392. } elseif (!empty($list['blackList']['domain'])) {
  1393. // Domains
  1394. foreach ($list['blackList']['domain'] as $domain) {
  1395. if (strpos($email, $domain)) {
  1396. $flag = true;
  1397. break;
  1398. }
  1399. }
  1400. }
  1401. // Whitelist
  1402. if ($flag) {
  1403. if (isset($email, $list['whiteList']['email']) && in_array($email, $list['whiteList']['email'])) {
  1404. // Emails
  1405. return false;
  1406. } elseif (isset($list['whiteList']['domain'])) {
  1407. // Domains
  1408. foreach ($list['whiteList']['domain'] as $domain) {
  1409. if (strpos($email, $domain)) {
  1410. $flag = false;
  1411. }
  1412. }
  1413. }
  1414. }
  1415. return $flag;
  1416. }
  1417. public function timeZoneConverter($dateFlag)
  1418. {
  1419. $website = $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'Knowledgebase']);
  1420. $timeZone = $website->getTimezone();
  1421. $timeFormat = $website->getTimeformat();
  1422. $activeUser = $this->container->get('user.service')->getSessionUser();
  1423. $agentTimeZone = !empty($activeUser) ? $activeUser->getTimezone() : null;
  1424. $agentTimeFormat = !empty($activeUser) ? $activeUser->getTimeformat() : null;
  1425. $parameterType = gettype($dateFlag);
  1426. if($parameterType == 'string'){
  1427. if(is_null($agentTimeZone) && is_null($agentTimeFormat)){
  1428. if(is_null($timeZone) && is_null($timeFormat)){
  1429. $datePattern = date_create($dateFlag);
  1430. return date_format($datePattern,'d-m-Y h:ia');
  1431. } else {
  1432. $dateFlag = new \DateTime($dateFlag);
  1433. $datePattern = $dateFlag->setTimezone(new \DateTimeZone($timeZone));
  1434. return date_format($datePattern, $timeFormat);
  1435. }
  1436. } else {
  1437. $dateFlag = new \DateTime($dateFlag);
  1438. $datePattern = $dateFlag->setTimezone(new \DateTimeZone($agentTimeZone));
  1439. return date_format($datePattern, $agentTimeFormat);
  1440. }
  1441. } else {
  1442. if(is_null($agentTimeZone) && is_null($agentTimeFormat)){
  1443. if(is_null($timeZone) && is_null($timeFormat)){
  1444. return date_format($dateFlag,'d-m-Y h:ia');
  1445. } else {
  1446. $datePattern = $dateFlag->setTimezone(new \DateTimeZone($timeZone));
  1447. return date_format($datePattern, $timeFormat);
  1448. }
  1449. } else {
  1450. $datePattern = $dateFlag->setTimezone(new \DateTimeZone($agentTimeZone));
  1451. return date_format($datePattern, $agentTimeFormat);
  1452. }
  1453. }
  1454. }
  1455. public function fomatTimeByPreference($dbTime,$timeZone,$timeFormat,$agentTimeZone,$agentTimeFormat)
  1456. {
  1457. if(is_null($agentTimeZone) && is_null($agentTimeFormat)) {
  1458. if(is_null($timeZone) && is_null($timeFormat)){
  1459. $dateTimeZone = $dbTime;
  1460. $timeFormatString = 'd-m-Y h:ia';
  1461. } else {
  1462. $dateTimeZone = $dbTime->setTimezone(new \DateTimeZone($timeZone));
  1463. $timeFormatString = $timeFormat;
  1464. }
  1465. } else {
  1466. $dateTimeZone = $dbTime->setTimezone(new \DateTimeZone($agentTimeZone));
  1467. $timeFormatString = $agentTimeFormat;
  1468. }
  1469. $time['dateTimeZone'] = $dateTimeZone;
  1470. $time['timeFormatString'] = $timeFormatString;
  1471. return $time;
  1472. }
  1473. public function isTicketAccessGranted(Ticket $ticket, User $user = null, $firewall = 'members')
  1474. {
  1475. // @TODO: Take current firewall into consideration (access check on behalf of agent/customer)
  1476. if (empty($user)) {
  1477. $user = $this->container->get('user.service')->getSessionUser();
  1478. }
  1479. if (empty($user)) {
  1480. return false;
  1481. } else {
  1482. $agentInstance = $user->getAgentInstance();
  1483. if (empty($agentInstance)) {
  1484. return false;
  1485. }
  1486. }
  1487. if ($agentInstance->getSupportRole()->getId() == 3 && in_array($agentInstance->getTicketAccessLevel(), [2, 3, 4])) {
  1488. $accessLevel = $agentInstance->getTicketAccessLevel();
  1489. // Check if user has been given inidividual access
  1490. if ($ticket->getAgent() != null && $ticket->getAgent()->getId() == $user->getId()) {
  1491. return true;
  1492. }
  1493. if ($accessLevel == 2 || $accessLevel == 3) {
  1494. // Check if user belongs to a support team assigned to ticket
  1495. $teamReferenceIds = array_map(function ($team) { return $team->getId(); }, $agentInstance->getSupportTeams()->toArray());
  1496. if ($ticket->getSupportTeam() != null && in_array($ticket->getSupportTeam()->getId(), $teamReferenceIds)) {
  1497. return true;
  1498. } else if ($accessLevel == 2) {
  1499. // Check if user belongs to a support group assigned to ticket
  1500. $groupReferenceIds = array_map(function ($group) { return $group->getId(); }, $agentInstance->getSupportGroups()->toArray());
  1501. if ($ticket->getSupportGroup() != null && in_array($ticket->getSupportGroup()->getId(), $groupReferenceIds)) {
  1502. return true;
  1503. }
  1504. }
  1505. }
  1506. return false;
  1507. }
  1508. return true;
  1509. }
  1510. public function addTicketCustomFields($thread, $submittedCustomFields = [], $uploadedFilesCollection = [])
  1511. {
  1512. $customFieldsService = null;
  1513. $customFieldsEntityReference = null;
  1514. if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  1515. $customFieldsService = $this->container->get('uvdesk_package_custom_fields.service');
  1516. $customFieldsEntityReference = UVDeskCommunityPackages\CustomFields\Entity\CustomFields::class;
  1517. $customFieldValuesEntityReference = UVDeskCommunityPackages\CustomFields\Entity\CustomFieldsValues::class;
  1518. $ticketCustomFieldValuesEntityReference = UVDeskCommunityPackages\CustomFields\Entity\TicketCustomFieldsValues::class;
  1519. } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  1520. $customFieldsService = $this->container->get('uvdesk_package_form_component.service');
  1521. $customFieldsEntityReference = UVDeskCommunityPackages\FormComponent\Entity\CustomFields::class;
  1522. $customFieldValuesEntityReference = UVDeskCommunityPackages\FormComponent\Entity\CustomFieldsValues::class;
  1523. $ticketCustomFieldValuesEntityReference = UVDeskCommunityPackages\FormComponent\Entity\TicketCustomFieldsValues::class;
  1524. } else {
  1525. return;
  1526. }
  1527. $ticket = $thread->getTicket();
  1528. $customFieldsCollection = $this->entityManager->getRepository($customFieldsEntityReference)->findAll();
  1529. $customFieldValuesEntityRepository = $this->entityManager->getRepository($customFieldValuesEntityReference);
  1530. foreach ($customFieldsCollection as $customFields) {
  1531. if (in_array($customFields->getFieldType(), ['select', 'checkbox', 'radio']) && !count($customFields->getCustomFieldValues())) {
  1532. continue;
  1533. }
  1534. if (
  1535. !empty($submittedCustomFields)
  1536. && $customFields->getFieldType() != 'file'
  1537. && isset($submittedCustomFields[$customFields->getId()])
  1538. ) {
  1539. // Check if custom field dependency criterias are fullfilled
  1540. if (
  1541. count($customFields->getCustomFieldsDependency())
  1542. && !in_array($ticket->getType(), $customFields->getCustomFieldsDependency()->toArray())
  1543. ) {
  1544. continue;
  1545. }
  1546. // Save ticket custom fields
  1547. $ticketCustomField = new $ticketCustomFieldValuesEntityReference();
  1548. $ticketCustomField
  1549. ->setTicket($ticket)
  1550. ->setTicketCustomFieldsValues($customFields)
  1551. ->setValue(json_encode($submittedCustomFields[$customFields->getId()]))
  1552. ;
  1553. if (in_array($customFields->getFieldType(), ['select', 'checkbox', 'radio'])) {
  1554. // Add custom field values mapping too
  1555. if (is_array($submittedCustomFields[$customFields->getId()])) {
  1556. foreach ($submittedCustomFields[$customFields->getId()] as $value) {
  1557. $ticketCustomFieldValues = $customFieldValuesEntityRepository->findOneBy([
  1558. 'id' => $value,
  1559. 'customFields' => $customFields,
  1560. ]);
  1561. if (!empty($ticketCustomFieldValues)) {
  1562. $ticketCustomField
  1563. ->setTicketCustomFieldValueValues($ticketCustomFieldValues)
  1564. ;
  1565. }
  1566. }
  1567. } else {
  1568. $ticketCustomFieldValues = $customFieldValuesEntityRepository->findOneBy([
  1569. 'id' => $submittedCustomFields[$customFields->getId()],
  1570. 'customFields' => $customFields,
  1571. ]);
  1572. if (!empty($ticketCustomFieldValues)) {
  1573. $ticketCustomField
  1574. ->setTicketCustomFieldValueValues($ticketCustomFieldValues)
  1575. ;
  1576. }
  1577. }
  1578. }
  1579. $this->entityManager->persist($ticketCustomField);
  1580. $this->entityManager->flush();
  1581. } else if (
  1582. !empty($uploadedFilesCollection)
  1583. && isset($uploadedFilesCollection[$customFields->getId()])
  1584. ) {
  1585. // Upload files
  1586. $path = '/custom-fields/ticket/' . $ticket->getId() . '/';
  1587. $fileNames = $this->fileUploadService->uploadFile($uploadedFilesCollection[$customFields->getid()], $path, true);
  1588. if (!empty($fileNames)) {
  1589. // Save files entry to attachment table
  1590. try {
  1591. $newFilesNames = $customFieldsService->addFilesEntryToAttachmentTable([$fileNames], $thread);
  1592. foreach ($newFilesNames as $value) {
  1593. // Save ticket custom fields
  1594. $ticketCustomField = new $ticketCustomFieldValuesEntityReference();
  1595. $ticketCustomField
  1596. ->setTicket($ticket)
  1597. ->setTicketCustomFieldsValues($customFields)
  1598. ->setValue(json_encode([
  1599. 'name' => $value['name'],
  1600. 'path' => $value['path'],
  1601. 'id' => $value['id'],
  1602. ]))
  1603. ;
  1604. $this->entityManager->persist($ticketCustomField);
  1605. $this->entityManager->flush();
  1606. }
  1607. } catch (\Exception $e) {
  1608. // @TODO: Log execption message
  1609. }
  1610. }
  1611. }
  1612. }
  1613. }
  1614. // return attachemnt for initial thread
  1615. public function getInitialThread($ticketId)
  1616. {
  1617. $firstThread = null;
  1618. $intialThread = $this->entityManager->getRepository(Thread::class)->findBy(['ticket'=>$ticketId]);
  1619. foreach ($intialThread as $key => $value) {
  1620. if ($value->getThreadType() == "create"){
  1621. $firstThread = $value;
  1622. }
  1623. }
  1624. return $firstThread;
  1625. }
  1626. }