PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.10.1
Fluent Support – Helpdesk & Customer Support Ticket System v1.10.1
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
fluent-support / app / Services / Helper.php

Helper.php in Fluent Support – Helpdesk & Customer Support Ticket System 1.10.1, at app/Services/Helper.php

1,456 lines 53.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Services;
4
5 use FluentSupport\App\App;
6 use FluentSupport\App\Models\Agent;
7 use FluentSupport\App\Models\Ticket;
8 use FluentSupport\App\Models\Conversation;
9 use FluentSupport\App\Models\Customer;
10 use FluentSupport\App\Models\MailBox;
11 use FluentSupport\App\Models\Meta;
12 use FluentSupport\App\Models\AIActivityLogs;
13 use FluentSupport\App\Models\Person;
14 use FluentSupport\App\Models\Product;
15 use FluentSupport\App\Services\Includes\UploadService;
16 use FluentSupport\App\Services\EmailNotification\Settings;
17 use FluentSupport\Framework\Support\Arr;
18
19 /**
20 * Helper - REST API Helper Class
21 *
22 * App helper for REST API
23 *
24 * @package FluentSupport\App\Services
25 *
26 * @version 1.0.0
27 */
28 class Helper
29 {
30 public static function FluentSupport($module = null)
31 {
32 return App::getInstance($module);
33 }
34
35 /**
36 * Get agent information by user id
37 * The function will get user id as parameter or get id from session and return agent information
38 * @param null $userId
39 * @return false | Agent
40 */
41 public static function getAgentByUserId($userId = null)
42 {
43 if ($userId === null) {
44 $userId = get_current_user_id();
45 }
46 if (!$userId) {
47 return false;
48 }
49 return Agent::where('user_id', $userId)->first();
50 }
51
52 /**
53 * This function will return the list of ticket priorities list for customer
54 *
55 * @return mixed
56 */
57 public static function customerTicketPriorities()
58 {
59 return apply_filters('fluent_support/customer_ticket_priorities', [
60 'normal' => __('Normal', 'fluent-support'),
61 'medium' => __('Medium', 'fluent-support'),
62 'critical' => __('Critical', 'fluent-support')
63 ]);
64 }
65
66 /**
67 * This function will return the list of ticket priorities list for Admin
68 *
69 * @return mixed
70 */
71 public static function adminTicketPriorities()
72 {
73 return apply_filters('fluent_support/admin_ticket_priorities', [
74 'normal' => __('Normal', 'fluent-support'),
75 'medium' => __('Medium', 'fluent-support'),
76 'critical' => __('Critical', 'fluent-support')
77 ]);
78 }
79
80
81 /**
82 * This function will return ticket status group
83 *
84 * @return mixed
85 */
86 public static function ticketStatusGroups()
87 {
88 return apply_filters('fluent_support/ticket_status_groups', [
89 'open' => ['new', 'active'],
90 'active' => ['active'],
91 'closed' => ['closed'],
92 'new' => ['new'],
93 'all' => []
94 ]);
95 }
96
97 /**
98 * This function will return custom ticket status group
99 *
100 * @return mixed
101 */
102 public static function changeableTicketStatuses()
103 {
104 $ticketStatus = static::ticketStatusGroups();
105
106 unset($ticketStatus['all']);
107 unset($ticketStatus['open']);
108
109 return apply_filters('fluent_support/changeable_ticket_statuses', $ticketStatus);
110 }
111
112 /**
113 * This function will return ticket status list
114 *
115 * @return mixed
116 */
117 public static function ticketStatuses()
118 {
119 return apply_filters('fluent_support/ticket_statuses', [
120 'new' => __('New', 'fluent-support'),
121 'active' => __('Active', 'fluent-support'),
122 'closed' => __('Closed', 'fluent-support'),
123 ]);
124 }
125
126 public static function getTkStatusesByGroupName($groupName)
127 {
128 $groups = self::ticketStatusGroups();
129 return Arr::get($groups, $groupName, []);
130 }
131
132 public static function ticketAcceptedFileMiles()
133 {
134 $groups = self::getMimeGroups();
135 $globalSettings = (new Settings())->globalBusinessSettings();
136
137 if (empty($globalSettings['accepted_file_types'])) {
138 return apply_filters('fluent_support/accepted_ticket_mimes', []);
139 }
140
141 $mimes = [];
142 $typesGroups = Arr::only($groups, $globalSettings['accepted_file_types']);
143 foreach ($typesGroups as $mimesGroup) {
144 $mimes = array_merge($mimes, $mimesGroup['mimes']);
145 }
146
147 return apply_filters('fluent_support/accepted_ticket_mimes', $mimes);
148 }
149
150 public static function getAcceptedMimeHeadings()
151 {
152 $groups = self::getMimeGroups();
153 $globalSettings = (new Settings())->globalBusinessSettings();
154
155 if (empty($globalSettings['accepted_file_types'])) {
156 return [];
157 }
158
159 $mimeNames = [];
160 $typesGroups = Arr::only($groups, $globalSettings['accepted_file_types']);
161 foreach ($typesGroups as $mimesGroup) {
162 $mimeNames[] = $mimesGroup['title'];
163 }
164
165 return $mimeNames;
166 }
167
168 public static function getFileUploadMessage()
169 {
170 $mimeHeadings = self::getAcceptedMimeHeadings();
171 $settings = (new Settings())->globalBusinessSettings();
172 $maxFileSize = floatval($settings['max_file_size']);
173
174 return sprintf(__('Supported Types: %s and max file size: %.01fMB', 'fluent-support'), implode(', ', $mimeHeadings), $maxFileSize);
175 }
176
177 public static function getMimeGroups()
178 {
179 return apply_filters('fluent_support/mime_groups', [
180 'images' => [
181 'title' => __('Photos', 'fluent-support'),
182 'mimes' => [
183 'image/gif',
184 'image/ief',
185 'image/jpeg',
186 'image/webp',
187 'image/pjpeg',
188 'image/ktx',
189 'image/png'
190 ]
191 ],
192 'csv' => [
193 'title' => __('CSV', 'fluent-support'),
194 'mimes' => [
195 'application/csv',
196 'application/txt',
197 'text/csv',
198 'text/plain',
199 'text/comma-separated-values',
200 'text/anytext',
201 ]
202 ],
203 'documents' => [
204 'title' => __('PDF/Docs', 'fluent-support'),
205 'mimes' => [
206 'application/excel',
207 'application/vnd.ms-excel',
208 'application/vnd.msexcel',
209 'application/octet-stream',
210 'application/pdf',
211 'application/msword',
212 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
213 ]
214 ],
215 'zip' => [
216 'title' => __('Zip', 'fluent-support'),
217 'mimes' => [
218 'application/zip'
219 ]
220 ],
221 'json' => [
222 'title' => __('JSON', 'fluent-support'),
223 'mimes' => [
224 'application/json',
225 'application/jsonml+json'
226 ]
227 ]
228 ]);
229 }
230
231 /**
232 * getOption method will return settings using key
233 * This method will get key as parameter, fetch data from database, beautify the data and return
234 * @param $key
235 * @param string $default
236 * @return mixed|string
237 */
238 public static function getOption($key, $default = '')
239 {
240 //Get settings from meta table using the key
241 $data = Meta::where('object_type', 'option')
242 ->where('key', $key)
243 ->first();
244
245 if ($data) {
246 $value = static::safeUnserialize($data->value);
247 if ($value) {
248 return $value;
249 }
250 }
251
252 return $default;
253 }
254
255 /**
256 * updateOption method will update or insert settings
257 * This method will get key and value as parameter, check exists or not. If exist update value by key, else insert value for the key
258 * @param $key
259 * @param $value
260 * @return mixed
261 */
262 public static function updateOption($key, $value)
263 {
264 //Get settings from meta table using the key
265 $data = Meta::where('object_type', 'option')
266 ->where('key', $key)
267 ->first();
268
269 //If data is available, update existing data and return
270 if ($data) {
271 return Meta::where('id', $data->id)
272 ->update([
273 'value' => maybe_serialize($value)
274 ]);
275 }
276
277 //If newly submit, create new record and return
278 return Meta::insert([
279 'object_type' => 'option',
280 'key' => $key,
281 'value' => maybe_serialize($value)
282 ]);
283 }
284
285 public static function deleteOption($key)
286 {
287 return Meta::where('object_type', 'option')
288 ->where('key', $key)
289 ->delete();
290 }
291
292 /**
293 * getIntegrationOption method will return the integration settings by integration key
294 * @param $key
295 * @param string $default
296 * @return mixed|string
297 */
298 public static function getIntegrationOption($key, $default = '')
299 {
300 $data = Meta::where('object_type', 'integration_settings')
301 ->where('key', $key)
302 ->first();
303
304 if ($data) {
305 $value = static::safeUnserialize($data->value);
306 if ($value) {
307 return $value;
308 }
309 }
310
311 return $default;
312 }
313
314 /**
315 * updateIntegrationOption method will update existing settings or create new settings by integration key
316 * @param $key
317 * @param $value
318 * @return mixed
319 */
320 public static function updateIntegrationOption($key, $value)
321 {
322 $data = Meta::where('object_type', 'integration_settings')
323 ->where('key', $key)
324 ->first();
325
326 if ($data) {
327 return Meta::where('id', $data->id)
328 ->update([
329 'value' => maybe_serialize($value)
330 ]);
331 }
332
333 return Meta::insert([
334 'object_type' => 'integration_settings',
335 'key' => $key,
336 'value' => maybe_serialize($value)
337 ]);
338 }
339
340 public static function getTicketViewUrl($ticket)
341 {
342 $baseUrl = self::getPortalBaseUrl();
343
344 return $baseUrl . '/#/ticket/' . $ticket->id . '/view';
345 }
346
347 public static function getTicketViewSignedUrl($ticket)
348 {
349 if (!self::isPublicSignedTicketEnabled()) {
350 return self::getTicketViewUrl($ticket);
351 }
352
353 $baseUrl = self::getPortalBaseUrl();
354
355 $baseUrl = add_query_arg([
356 'fs_view' => 'ticket',
357 'support_hash' => $ticket->hash,
358 'ticket_id' => $ticket->id
359 ], $baseUrl);
360
361 return $baseUrl . '#/ticket/' . $ticket->id . '/view';
362 }
363
364 public static function saveOpenAIData($objectType, $key, $data)
365 {
366 $serializedData = maybe_serialize($data);
367
368 $previousValue = Meta::where('object_type', $objectType)->first();
369
370 if ($previousValue) {
371 return Meta::where('object_type', $objectType)->update([
372 'value' => $serializedData
373 ]);
374 } else {
375 return Meta::insert([
376 'object_type' => $objectType,
377 'key' => $key,
378 'value' => $serializedData
379 ]);
380 }
381
382 }
383
384 public static function authorizeChatGPTAPIKey($data)
385 {
386 return wp_remote_get('https://api.openai.com/v1/models', [
387 'headers' => [
388 'Authorization' => 'Bearer ' . $data['api_key'],
389 'Content-Type' => 'application/json'
390 ]
391 ]);
392 }
393
394 public static function isPublicSignedTicketEnabled()
395 {
396 $businessSettings = self::getBusinessSettings();
397
398 return (Arr::get($businessSettings, 'disable_public_ticket') != 'yes');
399 }
400
401 public static function getTicketAdminUrl($ticket)
402 {
403 $baseUrl = self::getPortalAdminBaseUrl();
404 return $baseUrl . 'tickets/' . $ticket->id . '/view';
405 }
406
407 /**
408 * getPortalBaseUrl will get the portal page id and return link of the page
409 * @return mixed
410 */
411 public static function getPortalBaseUrl()
412 {
413 $businessSettings = self::getBusinessSettings();
414 $baseUrl = get_permalink($businessSettings['portal_page_id']);
415 $baseUrl = rtrim($baseUrl, '/\\');
416 return apply_filters('fluent_support/portal_base_url', $baseUrl);
417 }
418
419 public static function getPortalAdminBaseUrl()
420 {
421 return apply_filters('fluent_support/portal_admin_base_url', admin_url('admin.php?page=fluent-support/#/'));
422 }
423
424 public static function getBusinessSettings($key = null)
425 {
426 static $settings;
427
428 if ($settings && $key) {
429 return Arr::get($settings, $key);
430 }
431
432 if ($settings) {
433 return $settings;
434 }
435
436 $settings = (new Settings())->globalBusinessSettings();
437
438 if ($key) {
439 return Arr::get($settings, $key);
440 }
441 return $settings;
442 }
443
444 public static function isAgentFeedbackEnabled()
445 {
446 return self::getBusinessSettings('agent_feedback_rating', 'no') == 'yes';
447 }
448
449 public static function getTicketMeta($ticketId, $key, $default = '')
450 {
451 $data = Meta::where('object_type', 'ticket_meta')
452 ->where('key', $key)
453 ->where('object_id', $ticketId)
454 ->first();
455
456 if ($data) {
457 $value = static::safeUnserialize($data->value);
458 if ($value) {
459 return $value;
460 }
461 }
462
463 return $default;
464 }
465
466 public static function updateTicketMeta($ticketId, $key, $value)
467 {
468 $data = Meta::where('object_type', 'ticket_meta')
469 ->where('key', $key)
470 ->where('object_id', $ticketId)
471 ->first();
472
473 if ($data) {
474 return Meta::where('id', $data->id)
475 ->update([
476 'value' => maybe_serialize($value)
477 ]);
478 }
479
480 return Meta::insert([
481 'object_type' => 'ticket_meta',
482 'object_id' => $ticketId,
483 'key' => $key,
484 'value' => maybe_serialize($value)
485 ]);
486 }
487
488 public static function getWPPages()
489 {
490 $pages = (self::FluentSupport())->app->db
491 ->table('posts')
492 ->select(['ID', 'post_title'])
493 ->where('post_type', 'page')
494 ->where('post_status', 'publish')
495 ->latest('ID')
496 ->get();
497 $formattedPages = [];
498 foreach ($pages as $page) {
499 $formattedPages[] = [
500 'id' => intval($page->ID),
501 'title' => $page->post_title ?: __('(no title)', 'fluent-support')
502 ];
503 }
504 return $formattedPages;
505 }
506
507 public static function getDefaultMailBox()
508 {
509 $mailbox = MailBox::where('is_default', 'yes')->first();
510
511 if ($mailbox) {
512 return $mailbox;
513 }
514
515 return MailBox::oldest('id')->first();
516 }
517
518 public static function getCurrentAgent()
519 {
520 // If user is logged in then return the agent by user id.
521 // This `get_current_user_id` function is WP function and
522 // it returns user id if user is logged in.
523 if (get_current_user_id()) {
524 return Agent::where('user_id', get_current_user_id())->first();
525 }
526 }
527
528 public static function getCurrentCustomer()
529 {
530 // If user is logged in then return the customer by user id.
531 // This `get_current_user_id` function is WP function and
532 // it returns user id if user is logged in.
533 if (get_current_user_id()) { //if user is logged in
534 return Customer::where('user_id', get_current_user_id())->first();
535 }
536 }
537
538 public static function getCurrentPerson()
539 {
540 // If user is logged in then return the person(agent/customer) by user id.
541 // This `get_current_user_id` function is WP function and
542 // it returns user id if user is logged in.
543 if (get_current_user_id()) {
544 return Person::where('user_id', get_current_user_id())
545 ->orderBy('id', 'ASC')
546 ->first();
547 }
548 return null;
549 }
550
551 public static function getCustomerByID($customerid)
552 {
553 return Customer::where('id', $customerid)->first();
554 }
555
556 public static function sanitizeOrderValue($orderType = '')
557 {
558 $orderBys = ['ASC', 'DESC'];
559
560 $orderType = trim(strtoupper($orderType));
561
562 return in_array($orderType, $orderBys) ? $orderType : 'DESC';
563 }
564
565 public static function getFluentCRMTagConfig()
566 {
567 if (!defined('FLUENTCRM')) {
568 return [
569 'can_add_tags' => false,
570 'tags' => [],
571 'lists' => [],
572 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/fluentcrm-logo.svg',
573 'icon' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/fluent-crm-icon.png',
574 ];
575 }
576
577 $canAddTags = \FluentCrm\App\Services\PermissionManager::currentUserCan('fcrm_manage_contacts');
578
579 $canAddTags = apply_filters('fluent_support/can_user_add_tags_to_customer', $canAddTags);
580 $crmTags = [];
581 $crmLists = [];
582 if ($canAddTags) {
583 $crmTags = \FluentCrm\App\Models\Tag::select(['id', 'title'])->oldest('title')->get();
584 $crmLists = \FluentCrm\App\Models\Lists::select(['id', 'title'])->oldest('title')->get();
585 }
586
587 $crmConfigs = [
588 'can_add_tags' => $canAddTags,
589 'tags' => $crmTags,
590 'lists' => $crmLists,
591 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/fluentcrm-logo.svg',
592 'icon' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/fluent-crm-icon.png',
593 ];
594
595 if (defined('FLUENTCRM')) {
596 $crmConfigs['contacts'] = []; //(new \FluentCrm\App\Models\Subscriber)->get();
597 }
598
599 return $crmConfigs;
600 }
601
602 /**
603 * getFluentCrmContactData method will get information from fluent crm using user email
604 * @param $customer
605 * @return array|false
606 */
607 public static function getFluentCrmContactData($customer)
608 {
609 if (!defined('FLUENTCRM')) {
610 return false;
611 }
612 //Get contact info from FluentCRM using customer email
613 $contact = \FluentCrmApi('contacts')->getContactByUserRef($customer->email);
614 if ($contact) {
615 $tags = $contact->tags;
616 $lists = $contact->lists;
617 $urlBase = apply_filters('fluentcrm_menu_url_base', admin_url('admin.php?page=fluentcrm-admin#/'));
618 $crmProfileUrl = $urlBase . 'subscribers/' . $contact->id;
619
620 //Return contact data
621 return [
622 'id' => $contact->id,
623 'first_name' => $contact->first_name,
624 'last_name' => $contact->last_name,
625 'full_name' => $contact->full_name,
626 'name_mismatch' => $contact->full_name != $customer->full_name,
627 'tags' => $tags,
628 'lists' => $lists,
629 'status' => $contact->status,
630 'stats' => $contact->stats(),
631 'view_url' => $crmProfileUrl
632 ];
633 }
634
635 return false;
636 }
637
638 public static function openAIIntegrationStatus() {
639 $chatGPTSettingsData = Meta::where('object_type', '_fs_openai_settings')->value('value');
640
641 if ($chatGPTSettingsData) {
642 $settings = static::safeUnserialize($chatGPTSettingsData);
643 return !empty($settings['api_key']);
644 }
645
646 return false;
647 }
648
649 public static function fluentBotIntegrationStatus()
650 {
651 $settings = static::safeUnserialize(
652 Meta::where('object_type', 'fluent_bot_settings')->value('value')
653 );
654
655 return !empty($settings['isEnabled']) && $settings['isEnabled'] === 'true';
656 }
657
658
659 public static function showTicketSummaryAdminBar()
660 {
661 $data = self::getOption('global_business_settings');
662
663 if ($data && isset($data["enable_admin_bar_summary"]) && $data["enable_admin_bar_summary"] == 'yes') {
664 return true;
665 }
666
667 return false;
668 }
669
670 public static function generateMessageID($email)
671 {
672 $emailParts = explode('@', $email);
673 if (count($emailParts) != 2) {
674 return false;
675 }
676
677 $emailDomain = $emailParts[1];
678 try {
679 return sprintf(
680 "<%s.%s@%s>",
681 base_convert((int)microtime(true), 10, 36),
682 base_convert(bin2hex(openssl_random_pseudo_bytes(8)), 16, 36),
683 $emailDomain
684 );
685 } catch (\Exception $exception) {
686 return false;
687 }
688 }
689
690 public static function getExportOptions()
691 {
692 $data = [
693 'Agent First Name' => __('Agent First Name', 'fluent-support'),
694 'Agent Last Name' => __('Agent Last Name', 'fluent-support'),
695 'Agent Full Name' => __('Agent Full Name', 'fluent-support'),
696 'Responses' => __('Responses', 'fluent-support'),
697 'Interactions' => __('Interactions', 'fluent-support'),
698 'Open Tickets' => __('Open Tickets', 'fluent-support'),
699 'Closed' => __('Closed', 'fluent-support'),
700 'Waiting Tickets' => __('Waiting Tickets', 'fluent-support'),
701 'Average Waiting' => __('Average Waiting', 'fluent-support'),
702 'Max Waiting' => __('Max Waiting', 'fluent-support'),
703 ];
704
705 if (Helper::isAgentFeedbackEnabled()) {
706 $data['Likes'] = __('Likes', 'fluent-support');
707 $data['Dislikes'] = __('Dislikes', 'fluent-support');
708 }
709
710 return $data;
711 }
712
713 public static function getAuthProvider()
714 {
715 if (defined('FLUENT_AUTH_PLUGIN_PATH')) {
716 $settings = \FluentAuth\App\Helpers\Helper::getAuthFormsSettings();
717 if ($settings['enabled'] == 'yes') {
718 return 'fluent_auth';
719 }
720 }
721
722 return 'fluent_support';
723 }
724
725 public static function getDriversKey(){
726 return [
727 'dropbox_settings',
728 'google_drive_settings',
729 'local'
730 ];
731 }
732
733
734 public static function getUploadDriverKey()
735 {
736 if (!defined('FLUENTSUPPORTPRO')) {
737 return 'local';
738 }
739
740 $driver = self::getOption('file_upload_driver');
741
742 if ($driver) {
743 return $driver;
744 }
745
746 // Now guess the driver and save it
747
748 // check if dropbox is enabled
749 $dropboxSettings = self::getIntegrationOption('dropbox_settings', null);
750 if ($dropboxSettings) {
751 $dropBoxEnabled = Meta::where('object_type', 'enabled_upload_drivers')
752 ->where('key', 'dropbox_settings')
753 ->where('value', 'yes')
754 ->first();
755
756 if ($dropBoxEnabled) {
757 $driver = 'dropbox';
758 self::updateOption('file_upload_driver', $driver);
759 return $driver;
760 }
761 }
762
763 // check if google drive is enabled
764 $googleDriveSettings = self::getIntegrationOption('google_drive_settings', null);
765
766 if ($googleDriveSettings) {
767 $googleDriveEnabled = Meta::where('object_type', 'enabled_upload_drivers')
768 ->where('key', 'google_drive_settings')
769 ->where('value', 'yes')
770 ->first();
771
772 if ($googleDriveEnabled) {
773 $driver = 'google_drive';
774 self::updateOption('file_upload_driver', $driver);
775 return $driver;
776 }
777 }
778
779 self::updateOption('file_upload_driver', 'local');
780 return 'local';
781 }
782
783 public static function getIntegrationStatuses()
784 {
785 $connections = [
786 'woocommerce' => [
787 'title' => __('WooCommerce', 'fluent-support'),
788 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/woocommerce.png',
789 'is_integrated' => defined('WC_PLUGIN_FILE'),
790 'description' => __('The most popular e-commerce platform for WordPress', 'fluent-support'),
791 'doc_url' => 'https://fluentsupport.com/docs/woocommerce-integration/',
792 ],
793 'fluent-cart' => [
794 'title' => __('Fluent Cart', 'fluent-support'),
795 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/fluent-cart.webp',
796 'is_integrated' => defined('FLUENTCART_VERSION'),
797 'description' => __('A New Era of eCommerce with WordPress', 'fluent-support'),
798 'doc_url' => 'https://fluentsupport.com/docs/fluentcart-integration/',
799 ],
800 'lifter-lms' => [
801 'title' => __('LifterLMS', 'fluent-support'),
802 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/lifter-lms.png',
803 'is_integrated' => defined('LLMS_PLUGIN_FILE'),
804 'description' => __('Course and e-learning platform built for WordPress', 'fluent-support'),
805 'doc_url' => 'https://fluentsupport.com/docs/lifterlms-integration/',
806 ],
807 'slack' => [
808 'title' => __('Slack', 'fluent-support'),
809 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/slack.png',
810 'is_integrated' => self::getFSIntegrationStatus('slack_settings'),
811 'description' => __('Business communication platform designed to scale', 'fluent-support'),
812 'doc_url' => 'https://fluentsupport.com/docs/managing-tickets-using-slack/',
813 ],
814 'pm-pro' => [
815 'title' => __('Paid Memberships Pro', 'fluent-support'),
816 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/pmpro.png',
817 'is_integrated' => defined('PMPRO_VERSION'),
818 'description' => __('The ultimate platform for any member-focused business', 'fluent-support'),
819 'doc_url' => 'https://fluentsupport.com/docs/paid-membership-pro-integration/',
820 ],
821 'tutor-lms' => [
822 'title' => __('Tutor LMS', 'fluent-support'),
823 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/tutor-lms.png',
824 'is_integrated' => defined('TUTOR_VERSION'),
825 'description' => __('Course and e-learning platform built for WordPress', 'fluent-support'),
826 'doc_url' => 'https://fluentsupport.com/docs/tutorlms-integration/',
827 ],
828 'telegram' => [
829 'title' => __('Telegram', 'fluent-support'),
830 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/telegram.jpeg',
831 'is_integrated' => self::getFSIntegrationStatus('telegram_settings'),
832 'description' => __('Business communication platform designed for security', 'fluent-support'),
833 'doc_url' => 'https://fluentsupport.com/docs/managing-tickets-using-telegram/',
834 ],
835 'fluent-crm' => [
836 'title' => __('FluentCRM', 'fluent-support'),
837 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/fluent-crm.png',
838 'is_integrated' => defined('FLUENTCRM'),
839 'description' => __('Self-hosted email and marketing automation for WordPress', 'fluent-support'),
840 'doc_url' => 'https://fluentsupport.com/docs/fluentcrm-integration/',
841 ],
842 'fluent-community' => [
843 'title' => __('Fluent Community', 'fluent-support'),
844 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/fluent-community.png',
845 'is_integrated' => defined('FLUENT_COMMUNITY_PLUGIN_VERSION'),
846 'description' => __('Build and manage vibrant online communities with integrated LMS features directly within WordPress.', 'fluent-support'),
847 'doc_url' => 'https://fluentsupport.com/docs/fluentcommunity-integration/',
848 ],
849 'fluent-forms' => [
850 'title' => __('Fluent FORMS', 'fluent-support'),
851 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/fluent-forms.png',
852 'is_integrated' => defined('FLUENTFORM'),
853 'description' => __('A robust form plugin suitable for any business', 'fluent-support'),
854 'doc_url' => 'https://fluentsupport.com/docs/fluent-form-integration/',
855 ],
856 'buddy-boss' => [
857 'title' => __('BuddyBoss', 'fluent-support'),
858 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/buddy-boss.png',
859 'is_integrated' => defined('BP_PLUGIN_DIR'),
860 'description' => __('Powerful platform for any member-focused business', 'fluent-support'),
861 'doc_url' => 'https://fluentsupport.com/docs/buddyboss-integration/'
862 ],
863 'discord' => [
864 'title' => __('Discord', 'fluent-support'),
865 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/discord.png',
866 'is_integrated' => self::getFSIntegrationStatus('discord_settings'),
867 'description' => __('Business communication platform designed for tech', 'fluent-support'),
868 'doc_url' => 'https://fluentsupport.com/docs/managing-tickets-using-discord/',
869 ],
870 'wishlist-member' => [
871 'title' => __('WishList Member', 'fluent-support'),
872 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/wishlist-member.png',
873 'is_integrated' => defined('WLM3_PLUGIN_VERSION'),
874 'description' => __('Powerful platform for any member-focused business', 'fluent-support'),
875 'doc_url' => 'https://fluentsupport.com/docs/wishlist-member-integration/',
876 ],
877 'easy-digital-downloads' => [
878 'title' => __('Easy Digital Downloads', 'fluent-support'),
879 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/easy-digital-downloads.png',
880 'is_integrated' => class_exists('\Easy_Digital_Downloads'),
881 'description' => __('The ultimate WordPress platform for digital products', 'fluent-support'),
882 'doc_url' => 'https://fluentsupport.com/docs/edd-integration/',
883 ],
884 'restrict-content-pro' => [
885 'title' => __('Restrict Content pro', 'fluent-support'),
886 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/restrict-content-pro.png',
887 'is_integrated' => class_exists('\Restrict_Content_Pro' ),
888 'description' => __('Powerful platform for any member-focused business', 'fluent-support'),
889 'doc_url' => 'https://fluentsupport.com/docs/restrict-content-pro-integration/',
890 ],
891 'better-docs' => [
892 'title' => __('BetterDocs', 'fluent-support'),
893 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/better-docs.png',
894 'is_integrated' => false,
895 'description' => __('The standard plugin for knowledge base and documentation', 'fluent-support'),
896 'doc_url' => 'https://fluentsupport.com/docs/betterdocs-integration/',
897 ],
898 'whatsapp' => [
899 'title' => __('WhatsApp', 'fluent-support'),
900 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/whatsapp.jpeg',
901 'is_integrated' => self::getFSIntegrationStatus('twilio_settings'),
902 'description' => __('Business communication platform designed for privacy', 'fluent-support'),
903 'doc_url' => 'https://fluentsupport.com/docs/whatsapp-integration-via-twilio/',
904 ],
905 'paymattic' => [
906 'title' => __('Paymattic', 'fluent-support'),
907 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/paymattic.png',
908 'is_integrated' => defined('WPPAYFORM_VERSION'),
909 'description' => __('All-in-one payment gateway designed for WordPress', 'fluent-support'),
910 'doc_url' => 'https://paymattic.com/docs/how-to-integrate-fluent-support-with-paymattic-in-wordpress/',
911 ],
912 'learn-dash' => [
913 'title' => __('LearnDash', 'fluent-support'),
914 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/learn-dash.png',
915 'is_integrated' => defined('LEARNDASH_VERSION'),
916 'description' => __('The leading course platform built for WordPress', 'fluent-support'),
917 'doc_url' => 'https://fluentsupport.com/docs/learndash-integration/',
918 ],
919 'learn-press' => [
920 'title' => __('LearnPress', 'fluent-support'),
921 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/learn-press.png',
922 'is_integrated' => defined('LP_PLUGIN_FILE'),
923 'description' => __('Course and e-learning platform built for WordPress', 'fluent-support'),
924 'doc_url' => 'https://fluentsupport.com/docs/learnpress-integration/',
925 ],
926 'google-drive' => [
927 'title' => __('Google Drive', 'fluent-support'),
928 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/google-drive.jpeg',
929 'is_integrated' => self::getFSIntegrationStatus('google_drive_settings'),
930 'description' => __('A cloud storage service by Google for storing, syncing, and sharing files.', 'fluent-support'),
931 'doc_url' => 'https://fluentsupport.com/docs/google-drive-integration/'
932 ],
933 'dropbox' => [
934 'title' => __('Dropbox', 'fluent-support'),
935 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/dropbox.png',
936 'is_integrated' => self::getFSIntegrationStatus('dropbox_settings'),
937 'description' => __('A cloud-based file storage and sharing service that allows users to store files online and sync them across devices.', 'fluent-support'),
938 'doc_url' => 'https://fluentsupport.com/docs/dropbox-integration/',
939 ],
940 'member-press' => [
941 'title' => __('MemberPress', 'fluent-support'),
942 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/member-press.png',
943 'is_integrated' => class_exists('MeprUtils'),
944 'description' => __('A WordPress plugin that enables the creation and management of membership sites, including content access control and subscription billing.', 'fluent-support'),
945 'doc_url' => 'https://fluentsupport.com/docs/memberpress-integration/'
946 ],
947 'google-recaptcha' => [
948 'title' => __('Google reCAPTCHA', 'fluent-support'),
949 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/google-recaptcha.png',
950 'is_integrated' => self::getFSIntegrationStatus('recaptcha_setting'),
951 'description' => __('A security service by Google designed to protect websites from bots and abuse by using challenges to distinguish between human and automated access.', 'fluent-support'),
952 'doc_url' => 'https://fluentsupport.com/docs/google-recaptcha-integration/',
953 ],
954 'fluent-boards' => [
955 'title' => __('FluentBoards', 'fluent-support'),
956 'logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/integrations/fluent-boards.png',
957 'is_integrated' => defined('FLUENT_BOARDS'),
958 'description' => __('A project management tool designed to streamline workflows and collaboration through customizable, kanban-style boards.', 'fluent-support'),
959 'doc_url' => '',
960 ],
961 ];
962
963 return $connections;
964 }
965
966 public static function getGlobalSettingsMenu()
967 {
968 $menu = [
969 [
970 'title' => __('Global Settings', 'fluent-support'),
971 'route_name' => 'global_settings',
972 'icon' => 'Document',
973 ],
974 [
975 'title' => __('Ticket Tags', 'fluent-support'),
976 'route_name' => 'tags',
977 'icon' => 'CollectionTag',
978 ],
979 [
980 'title' => __('Ticket Form Config', 'fluent-support'),
981 'route_name' => 'ticket-form-config',
982 'icon' => 'Setting',
983 ],
984 [
985 'title' => __('Custom Fields', 'fluent-support'),
986 'route_name' => 'custom_fields',
987 'icon' => 'Tickets',
988 ],
989 [
990 'title' => __('Products', 'fluent-support'),
991 'route_name' => 'products',
992 'icon' => 'Goods',
993 ],
994 [
995 'title' => __('Support Staff', 'fluent-support'),
996 'route_name' => 'support-staffs',
997 'icon' => 'User',
998 ],
999 [
1000 'title' => __('FluentCRM Integration', 'fluent-support'),
1001 'route_name' => 'fluentcrm_integration',
1002 'icon' => 'Cpu',
1003 ],
1004 [
1005 'title' => __('Incoming Webhook', 'fluent-support'),
1006 'route_name' => 'incoming-webhook',
1007 'icon' => 'Connection',
1008 ],
1009 [
1010 'title' => __('Notification Integrations', 'fluent-support'),
1011 'route_name' => 'integration',
1012 'icon' => 'AlarmClock',
1013 ],
1014 [
1015 'title' => __('File Upload Integrations', 'fluent-support'),
1016 'route_name' => 'upload_integration',
1017 'icon' => 'FolderAdd',
1018 ],
1019 [
1020 'title' => __('Auto Close Settings', 'fluent-support'),
1021 'route_name' => 'auto_close',
1022 'icon' => 'Timer',
1023 ],
1024 [
1025 'title' => __('Ticket Importer', 'fluent-support'),
1026 'route_name' => 'ticket_importer',
1027 'icon' => 'Download',
1028 ],
1029 [
1030 'title' => __('Recaptcha', 'fluent-support'),
1031 'route_name' => 'reCaptcha',
1032 'icon' => 'Key',
1033 ],
1034 [
1035 'title' => __('Integration Statuses', 'fluent-support'),
1036 'route_name' => 'integration_statuses',
1037 'icon' => 'Connection',
1038 ],
1039 [
1040 'title' => __('OpenAI Integration', 'fluent-support'),
1041 'route_name' => 'openai_integration',
1042 'icon' => 'Connection',
1043 ],
1044 ];
1045
1046 if (defined('FLUENT_SUPPORT_PRO_DIR_FILE')) {
1047 $menu[] = [
1048 'title' => __('License Management', 'fluent-support'),
1049 'route_name' => 'license',
1050 'icon' => 'Lock',
1051 ];
1052 }
1053
1054 return apply_filters('fluent_support/settings_menu_items', $menu);
1055 }
1056
1057 public static function getFSIntegrationStatus($connection_name)
1058 {
1059 $integrationMap = [
1060 'slack_settings' => 'slack_settings',
1061 'discord_settings' => 'discord_settings',
1062 'twilio_settings' => 'twilio_settings',
1063 'telegram_settings' => 'telegram_settings',
1064 'google_drive_settings' => 'google_drive_settings',
1065 'dropbox_settings' => 'dropbox_settings',
1066 'recaptcha_setting' => '_fs_recaptcha_settings'
1067 ];
1068
1069 if (array_key_exists($connection_name, $integrationMap)) {
1070 if ($connection_name == 'google_drive_settings' || $connection_name == 'dropbox_settings') {
1071 return self::checkUploadDriverStatus($connection_name);
1072 } elseif ($connection_name == 'recaptcha_setting') {
1073 return self::checkRecaptchaStatus();
1074 } else {
1075 return self::checkNotificationIntegrationStatus($integrationMap[$connection_name]);
1076 }
1077 }
1078
1079 return false;
1080 }
1081
1082 private static function checkNotificationIntegrationStatus($settingName)
1083 {
1084 $settings = self::getIntegrationOption($settingName, null);
1085 if ($settings) {
1086 $status = Arr::get($settings, 'status', false);
1087 return $status ? true : false;
1088 }
1089 return false;
1090 }
1091
1092 private static function checkUploadDriverStatus($settingName)
1093 {
1094 $settings = self::getIntegrationOption($settingName, null);
1095 if ($settings) {
1096 $enabled = Arr::get($settings, 'status', false);
1097 return $enabled ? true : false;
1098 }
1099 return false;
1100 }
1101
1102 private static function checkRecaptchaStatus()
1103 {
1104 $reCaptchaSettingsData = Meta::where('object_type', '_fs_recaptcha_settings')->first();
1105
1106 if ($reCaptchaSettingsData) {
1107 $settings = static::safeUnserialize($reCaptchaSettingsData->value);
1108 $status = Arr::get($settings, 'is_enabled', false);
1109 return $status == 'true' ? true : false;
1110 }
1111 return false;
1112 }
1113
1114 public static function getAIActivities($data)
1115 {
1116 $page = isset($data['page']) ? intval($data['page']) : 1;
1117 $perPage = isset($data['per_page']) ? intval($data['per_page']) : 10;
1118
1119 $activitiesQuery = AIActivityLogs::with([
1120 'person' => function ($query) {
1121 $query->select(['first_name', 'person_type', 'last_name', 'id', 'avatar']);
1122 },
1123 'ticket' => function ($query) {
1124 $query->select(['id', 'title']);
1125 }
1126 ])->latest('id');
1127
1128 $from = sanitize_text_field( Arr::get( $data, 'from', '' ) );
1129 $to = sanitize_text_field( Arr::get( $data, 'to', '') );
1130
1131 if ( $from != $to ) {
1132 $from = $from . ' ' . '00:00:00';
1133 $to = $to . ' ' . '23:59:59';
1134 }
1135
1136 if ( ( !empty($from) && !empty($to) ) && $from == $to ) {
1137 $activitiesQuery->whereDate('created_at', '=', $from);
1138 } elseif (!empty($from) && !empty($to)) {
1139 $activitiesQuery->whereBetween('created_at', [ $from, $to ]);
1140 }
1141
1142 $agentId = intval( Arr::get($data, 'filters.agent_id') );
1143
1144 if ($agentId) {
1145 $activitiesQuery->where('agent_id', $agentId);
1146 }
1147
1148 return $activitiesQuery->paginate($perPage, ['*'], 'page', $page);
1149 }
1150
1151 public static function updateAISettings($settings)
1152 {
1153 $defaults = [
1154 'delete_days' => 14,
1155 'disable_logs' => 'no'
1156 ];
1157
1158 $settings = wp_parse_args($settings, $defaults);
1159 $settings['delete_days'] = (int)$settings['delete_days'];
1160
1161 Helper::updateOption('_ai_activity_settings', $settings);
1162
1163 return [
1164 'message' => __('AI Activity settings has been updated', 'fluent-support')
1165 ];
1166 }
1167
1168 public static function getSettings()
1169 {
1170 $settings = Helper::getOption('_ai_activity_settings', []);
1171
1172 $defaults = [
1173 'delete_days' => 14,
1174 'disable_logs' => 'no'
1175 ];
1176
1177 $settings = wp_parse_args($settings, $defaults);
1178
1179 if (! $settings ) throw new \Exception('No activity settings found');
1180
1181 return [
1182 'ai_activity_settings' => $settings
1183 ];
1184 }
1185
1186 public static function getIp($anonymize = false)
1187 {
1188 static $ipAddress;
1189
1190 if ($ipAddress) {
1191 return $ipAddress;
1192 }
1193
1194 if (empty($_SERVER['REMOTE_ADDR'])) {
1195 // It's a local cli request
1196 return '127.0.0.1';
1197 }
1198
1199 $ipAddress = '';
1200 if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
1201 //If it's a valid Cloudflare request
1202 if (self::isCfIp($_SERVER['REMOTE_ADDR'])) {
1203 //Use the CF-Connecting-IP header.
1204 $ipAddress = $_SERVER['HTTP_CF_CONNECTING_IP'];
1205 } else {
1206 //If it isn't valid, then use REMOTE_ADDR.
1207 $ipAddress = $_SERVER['REMOTE_ADDR'];
1208 }
1209 } else if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
1210 // most probably it's local reverse proxy
1211 if (isset($_SERVER["HTTP_CLIENT_IP"])) {
1212 $ipAddress = $_SERVER["HTTP_CLIENT_IP"];
1213 } else if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
1214 $ipAddress = (string)rest_is_ip_address(trim(current(preg_split('/,/', sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR']))))));
1215 }
1216 }
1217
1218 if (!$ipAddress) {
1219 $ipAddress = $_SERVER['REMOTE_ADDR'];
1220 }
1221
1222 $ipAddress = preg_replace('/^(\d+\.\d+\.\d+\.\d+):\d+$/', '\1', $ipAddress);
1223
1224 $ipAddress = apply_filters('fluent_auth/user_ip', $ipAddress);
1225
1226 if ($anonymize) {
1227 return wp_privacy_anonymize_ip($ipAddress);
1228 }
1229
1230 $ipAddress = sanitize_text_field(wp_unslash($ipAddress));
1231
1232 return $ipAddress;
1233 }
1234
1235 public static function isCfIp($ip = '')
1236 {
1237 if (!$ip) {
1238 $ip = $_SERVER['REMOTE_ADDR'];
1239 }
1240 $cloudflareIPRanges = array(
1241 '103.21.244.0/22',
1242 '103.22.200.0/22',
1243 '103.31.4.0/22',
1244 '104.16.0.0/13',
1245 '104.24.0.0/14',
1246 '108.162.192.0/18',
1247 '131.0.72.0/22',
1248 '141.101.64.0/18',
1249 '162.158.0.0/15',
1250 '172.64.0.0/13',
1251 '173.245.48.0/20',
1252 '188.114.96.0/20',
1253 '190.93.240.0/20',
1254 '197.234.240.0/22',
1255 '198.41.128.0/17'
1256 );
1257 $validCFRequest = false;
1258 //Make sure that the request came via Cloudflare.
1259 foreach ($cloudflareIPRanges as $range) {
1260 //Use the ip_in_range function from Joomla.
1261 if (self::ipInRange($ip, $range)) {
1262 //IP is valid. Belongs to Cloudflare.
1263 return true;
1264 }
1265 }
1266
1267 return false;
1268 }
1269
1270 private static function ipInRange($ip, $range)
1271 {
1272 if (strpos($range, '/') !== false) {
1273 // $range is in IP/NETMASK format
1274 list($range, $netmask) = explode('/', $range, 2);
1275 if (strpos($netmask, '.') !== false) {
1276 // $netmask is a 255.255.0.0 format
1277 $netmask = str_replace('*', '0', $netmask);
1278 $netmask_dec = ip2long($netmask);
1279 return ((ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec));
1280 } else {
1281 // $netmask is a CIDR size block
1282 // fix the range argument
1283 $x = explode('.', $range);
1284 while (count($x) < 4) $x[] = '0';
1285 list($a, $b, $c, $d) = $x;
1286 $range = sprintf("%u.%u.%u.%u", empty($a) ? '0' : $a, empty($b) ? '0' : $b, empty($c) ? '0' : $c, empty($d) ? '0' : $d);
1287 $range_dec = ip2long($range);
1288 $ip_dec = ip2long($ip);
1289
1290 # Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
1291 #$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));
1292
1293 # Strategy 2 - Use math to create it
1294 $wildcard_dec = pow(2, (32 - $netmask)) - 1;
1295 $netmask_dec = ~$wildcard_dec;
1296
1297 return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
1298 }
1299 } else {
1300 // range might be 255.255.*.* or 1.2.3.0-1.2.3.255
1301 if (strpos($range, '*') !== false) { // a.b.*.* format
1302 // Just convert to A-B format by setting * to 0 for A and 255 for B
1303 $lower = str_replace('*', '0', $range);
1304 $upper = str_replace('*', '255', $range);
1305 $range = "$lower-$upper";
1306 }
1307
1308 if (strpos($range, '-') !== false) { // A-B format
1309 list($lower, $upper) = explode('-', $range, 2);
1310 $lower_dec = (float)sprintf("%u", ip2long($lower));
1311 $upper_dec = (float)sprintf("%u", ip2long($upper));
1312 $ip_dec = (float)sprintf("%u", ip2long($ip));
1313 return (($ip_dec >= $lower_dec) && ($ip_dec <= $upper_dec));
1314 }
1315 return false;
1316 }
1317 }
1318
1319 public static function loadView($template, $data)
1320 {
1321 extract($data, EXTR_OVERWRITE);
1322
1323 $template = sanitize_file_name($template);
1324
1325 $template = str_replace('.', DIRECTORY_SEPARATOR, $template);
1326
1327 ob_start();
1328 include FLUENT_SUPPORT_PLUGIN_PATH . 'app/Views/emails/' . $template . '.php';
1329 return ob_get_clean();
1330 }
1331
1332 public static function isProductRequired()
1333 {
1334 $settings = Helper::getOption('_ticket_form_settings', []);
1335 return Arr::get($settings, 'product_required_field') === 'yes';
1336 }
1337
1338 public static function getBusinessBox()
1339 {
1340 $businessEmailBoxes = MailBox::select(['id', 'name', 'email', 'mapped_email'])
1341 ->where('box_type', 'email')
1342 ->get();
1343 return $businessEmailBoxes;
1344 }
1345
1346 public static function tempImageMoveUploadDir($ticketId, $contentType, $replyId = null)
1347 {
1348 // Fetch content based on the content type
1349 $content = self::getContentByType($ticketId, $contentType , $replyId);
1350 if (empty($content)) {
1351 return;
1352 }
1353
1354 // Extract image URLs from the content
1355 $imageUrls = self::extractImageUrls($content);
1356 if (empty($imageUrls)) {
1357 return;
1358 }
1359
1360 // Move images to the upload directory and update content
1361 self::moveImagesAndUpdateContent($imageUrls, $ticketId, $contentType, $content, $replyId);
1362 }
1363
1364 /**
1365 * Fetch content based on the content type.
1366 */
1367 private static function getContentByType($ticketId, $contentType, $replyId)
1368 {
1369 if ($contentType == 'ticket-create') {
1370 $ticket = Ticket::find($ticketId);
1371 return $ticket ? $ticket->content : null;
1372 }
1373
1374 $conversation = Conversation::find($replyId);
1375 return $conversation ? $conversation->content : null;
1376 }
1377
1378 /**
1379 * Extract image URLs from the content.
1380 */
1381 private static function extractImageUrls($content)
1382 {
1383 preg_match_all('/<img[^>]+src="([^">]+)"/', $content, $matches);
1384 return $matches[1] ?? [];
1385 }
1386
1387 /**
1388 * Move images to the upload directory and update content.
1389 */
1390 private static function moveImagesAndUpdateContent($imageUrls, $ticketId, $contentType, $content, $replyId)
1391 {
1392 // Get the current site's upload directory
1393 $uploadDirInfo = wp_upload_dir();
1394 $uploadsDir = $uploadDirInfo['basedir'];
1395 $tempDir = $uploadsDir . '/fluent-support/temp_files/';
1396
1397 foreach ($imageUrls as $imageUrl) {
1398 // Build the absolute path for the temporary file
1399 $imageRelativePath = $tempDir . basename($imageUrl);
1400 $absolutePath = $imageRelativePath;
1401
1402 // Move the file to the ticket-specific folder
1403 $newFileInfo = UploadService::copyFileTicketFolder($absolutePath, $ticketId);
1404
1405 // Check if the move was successful
1406 if (empty($newFileInfo['file_path'])) {
1407 continue; // Skip if the file couldn't be copied
1408 }
1409
1410 // Ensure the new URL is correctly constructed
1411 $newFileInfo['url'] = trailingslashit($uploadDirInfo['baseurl']) . 'fluent-support/ticket_' . $ticketId . '/' . basename($newFileInfo['file_path']);
1412
1413 // Replace the old URL with the new one in the content
1414 $content = str_replace($imageUrl, $newFileInfo['url'], $content);
1415 }
1416
1417 // Save the updated content
1418 self::saveUpdatedContent($ticketId, $contentType, $content, $replyId);
1419 }
1420
1421 /**
1422 * Save the updated content based on the content type.
1423 */
1424 private static function saveUpdatedContent($ticketId, $contentType, $content, $replyId)
1425 {
1426 if ($contentType == 'ticket-create') {
1427 $ticket = Ticket::find($ticketId);
1428 if ($ticket) {
1429 $ticket->content = $content;
1430 $ticket->save();
1431 }
1432 } else {
1433 $conversation = Conversation::find($replyId);
1434 if ($conversation) {
1435 $conversation->content = $content;
1436 $conversation->save();
1437 }
1438 }
1439 }
1440
1441 /**
1442 * Safely unserialize data.
1443 *
1444 * @param string $data The serialized data.
1445 * @return mixed The unserialized data or the original data if not serialized.
1446 */
1447 public static function safeUnserialize($data)
1448 {
1449 if (is_serialized($data)) { // Don't attempt to unserialize data that wasn't serialized going in.
1450 return @unserialize(trim($data), ['allowed_classes' => false]);
1451 }
1452
1453 return $data;
1454 }
1455 }
1456