PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.10.3
Fluent Support – Helpdesk & Customer Support Ticket System v1.10.3
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 / Integrations / FluentForm / FeedIntegration.php

FeedIntegration.php in Fluent Support – Helpdesk & Customer Support Ticket System 1.10.3, at app/Services/Integrations/FluentForm/FeedIntegration.php

492 lines 19.7 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\Integrations\FluentForm;
4
5 use FluentForm\App\Http\Controllers\IntegrationManagerController;
6 use FluentSupport\App\App;
7 use FluentSupport\App\Models\Attachment;
8 use FluentSupport\App\Models\Customer;
9 use FluentSupport\App\Models\MailBox;
10 use FluentSupport\App\Models\Product;
11 use FluentSupport\App\Models\Ticket;
12 use FluentSupport\Framework\Support\Arr;
13
14 class FeedIntegration extends IntegrationManagerController
15 {
16
17 public $hasGlobalMenu = false;
18
19 public $disableGlobalSettings = 'yes';
20
21 public function __construct($app = null)
22 {
23 parent::__construct(
24 $app,
25 'FluentSupport',
26 'fluent_support',
27 '_fluentsupport_settings',
28 'fluentform_fluentsupport_feed',
29 16
30 );
31
32 $app = App::getInstance();
33
34 $assets = $app['url.assets'];
35
36 $this->logo = $assets.'/images/fluent-support-color-logo.png';
37
38 $this->description = __('Create Support Ticket From Your Form Submission in FluentSupport', 'fluent-support');
39
40 $this->registerAdminHooks();
41
42 add_filter('fluentform/notifying_async_fluent_support', '__return_false');
43
44 }
45
46 public function pushIntegration($integrations, $formId)
47 {
48 $integrations[$this->integrationKey] = [
49 'title' => $this->title . ' Integration',
50 'logo' => $this->logo,
51 'is_active' => $this->isConfigured(),
52 'configure_title' => __('Configuration required!', 'fluent-support'),
53 'global_configure_url' => '#',
54 'configure_message' => __('FluentSupport is not configured yet! Please configure your FluentSupport api first', 'fluent-support'),
55 'configure_button_text' => __('Set FluentSupport', 'fluent-support')
56 ];
57 return $integrations;
58 }
59
60 public function getIntegrationDefaults($settings, $formId)
61 {
62 return [
63 'name' => '',
64 'first_name' => '',
65 'last_name' => '',
66 'email' => '',
67 'list_id' => '', // this is the business ID
68 'ticket_title' => '',
69 'ticket_body' => '',
70 'client_priority' => '',
71 'attachments' => '',
72 'product_id' => '',
73 'product_id_selection_type' => 'simple',
74 'product_routers' => [],
75 'customer_other_fields' => [
76 [
77 'item_value' => '',
78 'label' => ''
79 ]
80 ],
81 'conditionals' => [
82 'conditions' => [],
83 'status' => false,
84 'type' => 'all'
85 ],
86 'enabled' => true
87 ];
88 }
89
90 public function getSettingsFields($settings, $formId)
91 {
92 $fieldOptions = [];
93 foreach (Customer::mappables() as $key => $column) {
94 $fieldOptions[$key] = $column;
95 }
96 return [
97 'fields' => [
98 [
99 'key' => 'name',
100 'label' => __('Feed Name', 'fluent-support'),
101 'required' => true,
102 'placeholder' => __('Your Feed Name', 'fluent-support'),
103 'component' => 'text'
104 ],
105 [
106 'key' => 'list_id',
107 'label' => __('Business', 'fluent-support'),
108 'placeholder' => __('Select Business', 'fluent-support'),
109 'tips' => __('Select the Business you would like to add your Support Ticket to.', 'fluent-support'),
110 'component' => 'select',
111 'required' => true,
112 'options' => $this->geMailBoxes(),
113 ],
114 [
115 'key' => 'product_id',
116 'require_list' => false,
117 'label' => __('Product', 'fluent-support'),
118 'placeholder' => __('Select Support Product', 'fluent-support'),
119 'component' => 'selection_routing',
120 'simple_component' => 'select',
121 'routing_input_type' => 'select',
122 'routing_key' => 'product_id_selection_type',
123 'settings_key' => 'product_routers',
124 'is_multiple' => false,
125 'labels' => [
126 'choice_label' => __('Enable Dynamic Product Selection', 'fluent-support'),
127 'input_label' => '',
128 'input_placeholder' => __('Set Product', 'fluent-support')
129 ],
130 'options' => $this->getProducts()
131 ],
132 [
133 'key' => 'ticket_title',
134 'require_list' => false,
135 'label' => __('Ticket Title', 'fluent-support'),
136 'placeholder' => __('Ticket Title', 'fluent-support'),
137 'component' => 'value_text'
138 ],
139 [
140 'key' => 'ticket_content',
141 'require_list' => false,
142 'label' => __('Ticket Content', 'fluent-support'),
143 'placeholder' => __('Ticket Content', 'fluent-support'),
144 'component' => 'value_textarea'
145 ],
146 [
147 'key' => 'ticket_attachments',
148 'require_list' => false,
149 'label' => __('Ticket Attachments', 'fluent-support'),
150 'Placeholder' => __('Ticket Attachments', 'fluent-support'),
151 'tips' => __('Please input your file upload or image upload field shortcode here', 'fluent-support'),
152 'component' => 'value_text'
153 ],
154 [
155 'key' => 'client_priority',
156 'require_list' => false,
157 'label' => __('Ticket Priority', 'fluent-support'),
158 'Placeholder' => __('Ticket Priority', 'fluent-support'),
159 'tips' => __('Make sure form field values match with Fluent Support priorities', 'fluent-support'),
160 'component' => 'value_text'
161 ],
162 $this->getCustomField(), //Getting Fluent Support Custom Field To Map
163 [
164 'component' => 'html_info',
165 'html_info' => '<h4>' . __('Please provide the ticket provider info. If user is logged in then it will use that info. For Public users you can set your customer info', 'fluent-support') . '</h4>'
166 ],
167 [
168 'key' => 'CustomerFields',
169 'require_list' => false,
170 'label' => __('Customer Data', 'fluent-support'),
171 'tips' => __('Please Map Your Customer Data for this form. If your customer already logged in you can leave this', 'fluent-support'),
172 'component' => 'map_fields',
173 'field_label_remote' => __('Support Customer Field', 'fluent-support'),
174 'field_label_local' => __('Form Field', 'fluent-support'),
175 'primary_fileds' => [
176 [
177 'key' => 'email',
178 'label' => __('Email Address', 'fluent-support'),
179 'required' => true,
180 'input_options' => 'emails'
181 ],
182 [
183 'key' => 'first_name',
184 'label' => __('First Name', 'fluent-support')
185 ],
186 [
187 'key' => 'last_name',
188 'label' => __('Last Name', 'fluent-support')
189 ]
190 ]
191 ],
192 [
193 'key' => 'customer_other_fields',
194 'require_list' => false,
195 'label' => __('Customer Other Fields', 'fluent-support'),
196 'tips' => __('Select which Fluent Forms fields pair with their<br /> respective Fluent Support fields.', 'fluent-support'),
197 'field_label_remote' => __('Fluent Support Field', 'fluent-support'),
198 'field_label_local' => __('Form Field', 'fluent-support'),
199 'component' => 'dropdown_many_fields',
200 'options' => $fieldOptions
201 ],
202 ],
203 'button_require_list' => false,
204 'integration_title' => $this->title
205 ];
206 }
207
208 private function geMailBoxes()
209 {
210 $items = MailBox::all();
211 $formattedItems = [];
212 foreach ($items as $item) {
213 $formattedItems[strval($item->id)] = $item->name;
214 }
215 return $formattedItems;
216 }
217
218 private function getProducts()
219 {
220 $products = Product::all();
221 $formattedProducts = [];
222 foreach ($products as $product) {
223 $formattedProducts[strval($product->id)] = $product->title;
224 }
225 return $formattedProducts;
226 }
227
228 private function getCustomField()
229 {
230 $customFields = apply_filters('fluent_support/ticket_custom_fields', []);
231 $fieldToExclude = apply_filters('fluent_support/custom_field_types', []);
232
233 if(empty($customFields)){
234 return[
235 'component' => 'html_info',
236 'html_info' => ''
237 ];
238 }
239
240 $fields = [];
241 foreach ($customFields as $customFieldKey=>$customFieldValue) {
242
243 if(in_array($customFieldValue['type'], array_keys($fieldToExclude))){
244 unset($customFieldValue);
245 }
246
247 $fields[] = [
248 'key' => $customFieldValue['slug'],
249 'label' => $customFieldValue['label']
250 ];
251 }
252
253 $fields = array_map('array_filter', $fields);
254 $fields = array_filter( $fields );
255
256 return [
257 'key' => 'TicketCustomFields',
258 'require_list' => false,
259 'label' => __('Ticket Custom Fields', 'fluent-support'),
260 'tips' => __('Please Map Your Ticket Custom Field Data for this form.', 'fluent-support'),
261 'component' => 'map_fields',
262 'field_label_remote' => __('Fluent Support Custom Field', 'fluent-support'),
263 'field_label_local' => __('Form Field', 'fluent-support'),
264 'primary_fileds' => $fields
265 ];
266 }
267
268 public function getMergeFields($list, $listId, $formId)
269 {
270 return [];
271 }
272
273 public function notify($feed, $formData, $entry, $form)
274 {
275 $data = $feed['processedValues'];
276
277 if (!empty($data['email']) && !is_email($data['email'])) {
278 $data['email'] = Arr::get($formData, $data['email']);
279 }
280
281 $ticketCustomField = array_filter($data, function($key) {
282 return strpos($key, 'cf_') === 0;
283 }, ARRAY_FILTER_USE_KEY);
284
285
286 $customFields = apply_filters('fluent_support/ticket_custom_fields', []);
287
288 foreach($customFields as $key => $field){
289 $type = $field['type'];
290 $slug = $field['slug'];
291 if(!isset($ticketCustomField[$slug])) {
292 continue;
293 }
294
295 if( $type=='checkbox' && array_key_exists($slug, $ticketCustomField)) {
296 $ticketCustomField[$slug] = explode(',', Arr::get($ticketCustomField, $slug));
297 } else {
298 $ticketCustomField[$slug] = Arr::get($ticketCustomField, $slug);
299 }
300 }
301
302 $ticketData = [
303 'product_source' => 'local',
304 'mailbox_id' => Arr::get($data, 'list_id'),
305 'title' => sanitize_text_field(wp_unslash(Arr::get($data, 'ticket_title'))),
306 'content' => wp_unslash(wp_kses_post(Arr::get($data, 'ticket_content'))),
307 'attachments' => sanitize_text_field(Arr::get($data, 'ticket_attachments')),
308 'client_priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority'))),
309 'priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority'))),
310 'custom_fields' => $ticketCustomField,
311 'source' => 'web'
312 ];
313
314 $selectedProductArray = (array) $this->getSelectedTagIds($data, $formData, 'product_id', 'product_id_selection_type', 'product_routers');
315
316 if($selectedProductArray) {
317 $selectedProduct = $selectedProductArray[0];
318 $ticketData['product_id'] = $selectedProduct;
319 }
320
321 $customerData = Arr::only($data, ['first_name', 'last_name', 'email']);
322
323 foreach (Arr::get($data, 'customer_other_fields') as $field) {
324 if ($field['item_value']) {
325 $customerData[$field['label']] = $field['item_value'];
326 }
327 }
328
329
330 $user = get_user_by('ID', get_current_user_id());
331
332 if(!$user) {
333 $user = get_user_by('email', $customerData['email']);
334 }
335
336 if($user) {
337 $customerData['email'] = $user->user_email;
338 $customerData['user_id'] = $user->ID;
339 }
340
341 if(empty($customerData['email'])) {
342 do_action('fluentform/log_data', [
343 'title' => $feed['settings']['name'],
344 'status' => 'failed',
345 'description' => __('Support ticket creation failed, because no valid customer email found', 'fluent-support'),
346 'parent_source_id' => $form->id,
347 'source_id' => $entry->id,
348 'component' => $this->integrationKey,
349 'source_type' => 'submission_item'
350 ]);
351 return false;
352 }
353
354 $customerData['last_ip_address'] = $entry->ip;
355
356 $customer = Customer::maybeCreateCustomer($customerData);
357
358 // Don't create a ticket if customer is blocked
359 if($this->isBlockedCustomer($customerData['email'])) {
360 do_action('fluentform/log_data', [
361 'title' => $feed['settings']['name'],
362 'status' => 'failed',
363 'description' => __('Support ticket creation failed, because customer email is blocked', 'fluent-support'),
364 'parent_source_id' => $form->id,
365 'source_id' => $entry->id,
366 'component' => $this->integrationKey,
367 'source_type' => 'submission_item'
368 ]);
369 return false;
370 }
371
372 $ticketData['customer_id'] = $customer->id;
373
374 $ticketData = apply_filters('fluent_support/create_ticket_data', $ticketData, $customer);
375 do_action('fluent_support/before_ticket_create', $ticketData, $customer);
376
377 $ticket = Ticket::create($ticketData);
378
379 if(defined('FLUENTSUPPORTPRO') && !empty($ticketData['custom_fields'])) {
380 $ticket->syncCustomFields($ticketData['custom_fields']);
381 /*
382 * This custom_fields is causing issues in all webhook to where we called $ticket->save()
383 * As we are calling $ticket->syncCustomFields() above, we don't need this anymore
384 * TODO: need to remove this line in future
385 */
386 //$ticket->custom_fields = $ticket->customData();
387 }
388
389 do_action('fluent_support/ticket_created', $ticket, $customer);
390
391 do_action('fluentform/log_data', [
392 'title' => $feed['settings']['name'],
393 'status' => 'success',
394 // translators: %d is the ticket ID number
395 'description' => sprintf(__('Support ticket has been created at Fluent Support. Ticket ID: %d', 'fluent-support'), $ticket->id),
396 'parent_source_id' => $form->id,
397 'source_id' => $entry->id,
398 'component' => $this->integrationKey,
399 'source_type' => 'submission_item'
400 ]);
401
402 if ($ticketData['attachments']) {
403 $attachments = is_array($ticketData['attachments'])
404 ? $ticketData['attachments']
405 : explode(',', $ticketData['attachments']);
406
407 $uploadDir = wp_upload_dir();
408
409 foreach ($attachments as $attachment) {
410 $attachment = trim($attachment);
411 if (empty($attachment)) {
412 continue;
413 }
414
415 $isMediaLibrary = false;
416 $attachmentId = null;
417
418 // Try to get attachment ID if it's a media library URL
419 $attachmentId = attachment_url_to_postid($attachment);
420 if ($attachmentId) {
421 $isMediaLibrary = true;
422 }
423
424 try {
425 if ($isMediaLibrary) {
426 $filePath = get_attached_file($attachmentId);
427 if (!$filePath) {
428 continue;
429 }
430 $fileName = basename($filePath);
431 $fileType = get_post_mime_type($attachmentId);
432 $fullUrl = wp_get_attachment_url($attachmentId);
433 } else {
434 $fileName = basename($attachment);
435 $filePath = $uploadDir['basedir'] . FLUENTFORM_UPLOAD_DIR . '/' . $fileName;
436 $fileInfo = wp_check_filetype($filePath);
437 $fileType = (!empty($fileInfo['type'])) ? $fileInfo['type'] : '';
438 $fullUrl = $attachment;
439 }
440
441 if (file_exists($filePath)) {
442 try {
443 Attachment::create([
444 'ticket_id' => $ticket->id,
445 'file_path' => sanitize_text_field($filePath),
446 'full_url' => sanitize_url($fullUrl),
447 'title' => sanitize_text_field($fileName),
448 'person_id' => $customer->id,
449 'file_type' => sanitize_text_field($fileType),
450 'is_media_library' => $isMediaLibrary,
451 'attachment_id' => $attachmentId
452 ]);
453 } catch (\Exception $e) {
454 error_log("Failed to create attachment record: " . $e->getMessage());
455 }
456 }
457 } catch (\Exception $e) {
458 error_log("Error processing attachment: " . $e->getMessage());
459 continue;
460 }
461 }
462
463 $ticket->load('attachments');
464 }
465
466 return true;
467 }
468
469 public function isConfigured()
470 {
471 return true;
472 }
473
474 public function isEnabled()
475 {
476 return true;
477 }
478
479 // check if customer is blocked or not
480 private function isBlockedCustomer($customerEmail)
481 {
482 $customer = Customer::where('email', $customerEmail)->first();
483
484 if('inactive' == $customer->status || !$customer->status) {
485 return true;
486 }
487
488 return false;
489 }
490
491 }
492