PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / trunk
Fluent Support – Helpdesk & Customer Support Ticket System vtrunk
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 trunk, at app/Services/Integrations/FluentForm/FeedIntegration.php

493 lines 19.6 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 $value = Arr::get($ticketCustomField, $slug, '');
297 $ticketCustomField[$slug] = $value ? explode(',', (string)$value) : [];
298 } else {
299 $ticketCustomField[$slug] = Arr::get($ticketCustomField, $slug);
300 }
301 }
302
303 $ticketData = [
304 'product_source' => 'local',
305 'mailbox_id' => Arr::get($data, 'list_id'),
306 // Feed settings and entry values are stored unslashed, so sanitize only.
307 'title' => sanitize_text_field(Arr::get($data, 'ticket_title')),
308 'content' => wp_kses_post(Arr::get($data, 'ticket_content')),
309 'attachments' => sanitize_text_field(Arr::get($data, 'ticket_attachments')),
310 'client_priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority', ''))),
311 'priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority', ''))),
312 'custom_fields' => $ticketCustomField,
313 'source' => 'web'
314 ];
315
316 $selectedProductArray = (array) $this->getSelectedTagIds($data, $formData, 'product_id', 'product_id_selection_type', 'product_routers');
317
318 if($selectedProductArray) {
319 $selectedProduct = $selectedProductArray[0];
320 $ticketData['product_id'] = $selectedProduct;
321 }
322
323 $customerData = Arr::only($data, ['first_name', 'last_name', 'email']);
324
325 foreach (Arr::get($data, 'customer_other_fields') as $field) {
326 if ($field['item_value']) {
327 $customerData[$field['label']] = $field['item_value'];
328 }
329 }
330
331
332 $user = get_user_by('ID', get_current_user_id());
333
334 if(!$user) {
335 $user = get_user_by('email', $customerData['email']);
336 }
337
338 if($user) {
339 $customerData['email'] = $user->user_email;
340 $customerData['user_id'] = $user->ID;
341 }
342
343 if(empty($customerData['email'])) {
344 do_action('fluentform/log_data', [
345 'title' => $feed['settings']['name'],
346 'status' => 'failed',
347 'description' => __('Support ticket creation failed, because no valid customer email found', 'fluent-support'),
348 'parent_source_id' => $form->id,
349 'source_id' => $entry->id,
350 'component' => $this->integrationKey,
351 'source_type' => 'submission_item'
352 ]);
353 return false;
354 }
355
356 $customerData['last_ip_address'] = $entry->ip;
357
358 $customer = Customer::maybeCreateCustomer($customerData);
359
360 // Don't create a ticket if customer is blocked
361 if($this->isBlockedCustomer($customerData['email'])) {
362 do_action('fluentform/log_data', [
363 'title' => $feed['settings']['name'],
364 'status' => 'failed',
365 'description' => __('Support ticket creation failed, because customer email is blocked', 'fluent-support'),
366 'parent_source_id' => $form->id,
367 'source_id' => $entry->id,
368 'component' => $this->integrationKey,
369 'source_type' => 'submission_item'
370 ]);
371 return false;
372 }
373
374 $ticketData['customer_id'] = $customer->id;
375
376 $ticketData = apply_filters('fluent_support/create_ticket_data', $ticketData, $customer);
377 do_action('fluent_support/before_ticket_create', $ticketData, $customer);
378
379 $ticket = Ticket::create($ticketData);
380
381 if(defined('FLUENTSUPPORTPRO') && !empty($ticketData['custom_fields'])) {
382 $ticket->syncCustomFields($ticketData['custom_fields']);
383 /*
384 * This custom_fields is causing issues in all webhook to where we called $ticket->save()
385 * As we are calling $ticket->syncCustomFields() above, we don't need this anymore
386 * TODO: need to remove this line in future
387 */
388 //$ticket->custom_fields = $ticket->customData();
389 }
390
391 do_action('fluent_support/ticket_created', $ticket, $customer);
392
393 do_action('fluentform/log_data', [
394 'title' => $feed['settings']['name'],
395 'status' => 'success',
396 // translators: %d is the ticket ID number
397 'description' => sprintf(__('Support ticket has been created at Fluent Support. Ticket ID: %d', 'fluent-support'), $ticket->id),
398 'parent_source_id' => $form->id,
399 'source_id' => $entry->id,
400 'component' => $this->integrationKey,
401 'source_type' => 'submission_item'
402 ]);
403
404 if ($ticketData['attachments']) {
405 $attachments = is_array($ticketData['attachments'])
406 ? $ticketData['attachments']
407 : explode(',', $ticketData['attachments']);
408
409 $uploadDir = wp_upload_dir();
410
411 foreach ($attachments as $attachment) {
412 $attachment = trim($attachment);
413 if (empty($attachment)) {
414 continue;
415 }
416
417 $isMediaLibrary = false;
418 $attachmentId = null;
419
420 // Try to get attachment ID if it's a media library URL
421 $attachmentId = attachment_url_to_postid($attachment);
422 if ($attachmentId) {
423 $isMediaLibrary = true;
424 }
425
426 try {
427 if ($isMediaLibrary) {
428 $filePath = get_attached_file($attachmentId);
429 if (!$filePath) {
430 continue;
431 }
432 $fileName = basename($filePath);
433 $fileType = get_post_mime_type($attachmentId);
434 $fullUrl = wp_get_attachment_url($attachmentId);
435 } else {
436 $fileName = basename($attachment);
437 $filePath = $uploadDir['basedir'] . FLUENTFORM_UPLOAD_DIR . '/' . $fileName;
438 $fileInfo = wp_check_filetype($filePath);
439 $fileType = (!empty($fileInfo['type'])) ? $fileInfo['type'] : '';
440 $fullUrl = $attachment;
441 }
442
443 if (file_exists($filePath)) {
444 try {
445 Attachment::create([
446 'ticket_id' => $ticket->id,
447 'file_path' => sanitize_text_field($filePath),
448 'full_url' => sanitize_url($fullUrl),
449 'title' => sanitize_text_field($fileName),
450 'person_id' => $customer->id,
451 'file_type' => sanitize_text_field($fileType),
452 'is_media_library' => $isMediaLibrary,
453 'attachment_id' => $attachmentId
454 ]);
455 } catch (\Exception $e) {
456
457 }
458 }
459 } catch (\Exception $e) {
460 continue;
461 }
462 }
463
464 $ticket->load('attachments');
465 }
466
467 return true;
468 }
469
470 public function isConfigured()
471 {
472 return true;
473 }
474
475 public function isEnabled()
476 {
477 return true;
478 }
479
480 // check if customer is blocked or not
481 private function isBlockedCustomer($customerEmail)
482 {
483 $customer = Customer::where('email', $customerEmail)->first();
484
485 if (!$customer) {
486 return false;
487 }
488
489 return $customer->isBlocked();
490 }
491
492 }
493