PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 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 All 69 releases
← All changes | app/Services/Integrations/FluentForm/FeedIntegration.php +161 -77 1.5.4 → 2.4.5 View file →
@@ -1,10 +1,9 @@
1 1 <?php
2 2
3 3 namespace FluentSupport\App\Services\Integrations\FluentForm;
4 4
5 -use FluentForm\App\Services\Integrations\IntegrationManager;
6 -use FluentForm\Framework\Foundation\Application;
5 +use FluentForm\App\Http\Controllers\IntegrationManagerController;
7 6 use FluentSupport\App\App;
8 7 use FluentSupport\App\Models\Attachment;
9 8 use FluentSupport\App\Models\Customer;
10 9 use FluentSupport\App\Models\MailBox;
@@ -11,9 +10,9 @@
11 10 use FluentSupport\App\Models\Product;
12 11 use FluentSupport\App\Models\Ticket;
13 12 use FluentSupport\Framework\Support\Arr;
14 13
15 -class FeedIntegration extends IntegrationManager
14 +class FeedIntegration extends IntegrationManagerController
16 15 {
17 16
18 17 public $hasGlobalMenu = false;
19 18
@@ -18,9 +17,9 @@
18 17 public $hasGlobalMenu = false;
19 18
20 19 public $disableGlobalSettings = 'yes';
21 20
22 - public function __construct(Application $app)
21 + public function __construct($app = null)
23 22 {
24 23 parent::__construct(
25 24 $app,
26 25 'FluentSupport',
@@ -35,13 +34,13 @@
35 34 $assets = $app['url.assets'];
36 35
37 36 $this->logo = $assets.'/images/fluent-support-color-logo.png';
38 37
39 - $this->description = __('Create Support Ticket From Your Form Submission in FluentSupport', 'fluentform');
38 + $this->description = __('Create Support Ticket From Your Form Submission in FluentSupport', 'fluent-support');
40 39
41 40 $this->registerAdminHooks();
42 41
43 - add_filter('fluentform_notifying_async_fluent_support', '__return_false');
42 + add_filter('fluentform/notifying_async_fluent_support', '__return_false');
44 43
45 44 }
46 45
47 46 public function pushIntegration($integrations, $formId)
@@ -49,12 +48,12 @@
49 48 $integrations[$this->integrationKey] = [
50 49 'title' => $this->title . ' Integration',
51 50 'logo' => $this->logo,
52 51 'is_active' => $this->isConfigured(),
53 - 'configure_title' => __('Configuration required!', 'fluentform'),
52 + 'configure_title' => __('Configuration required!', 'fluent-support'),
54 53 'global_configure_url' => '#',
55 - 'configure_message' => __('FluentSupport is not configured yet! Please configure your FluentSupport api first', 'fluentform'),
56 - 'configure_button_text' => __('Set FluentSupport', 'fluentform')
54 + 'configure_message' => __('FluentSupport is not configured yet! Please configure your FluentSupport api first', 'fluent-support'),
55 + 'configure_button_text' => __('Set FluentSupport', 'fluent-support')
57 56 ];
58 57 return $integrations;
59 58 }
60 59
@@ -97,18 +96,18 @@
97 96 return [
98 97 'fields' => [
99 98 [
100 99 'key' => 'name',
101 - 'label' => __('Feed Name', 'fluentform'),
100 + 'label' => __('Feed Name', 'fluent-support'),
102 101 'required' => true,
103 - 'placeholder' => __('Your Feed Name', 'fluentform'),
102 + 'placeholder' => __('Your Feed Name', 'fluent-support'),
104 103 'component' => 'text'
105 104 ],
106 105 [
107 106 'key' => 'list_id',
108 - 'label' => __('Business', 'fluentform'),
109 - 'placeholder' => __('Select Business', 'fluentform'),
110 - 'tips' => __('Select the Business you would like to add your Support Ticket to.', 'fluentform'),
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'),
111 110 'component' => 'select',
112 111 'required' => true,
113 112 'options' => $this->geMailBoxes(),
114 113 ],
@@ -114,10 +113,10 @@
114 113 ],
115 114 [
116 115 'key' => 'product_id',
117 116 'require_list' => false,
118 - 'label' => __('Product', 'fluentform'),
119 - 'placeholder' => __('Select Support Product', 'fluentform'),
117 + 'label' => __('Product', 'fluent-support'),
118 + 'placeholder' => __('Select Support Product', 'fluent-support'),
120 119 'component' => 'selection_routing',
121 120 'simple_component' => 'select',
122 121 'routing_input_type' => 'select',
123 122 'routing_key' => 'product_id_selection_type',
@@ -123,11 +122,11 @@
123 122 'routing_key' => 'product_id_selection_type',
124 123 'settings_key' => 'product_routers',
125 124 'is_multiple' => false,
126 125 'labels' => [
127 - 'choice_label' => __('Enable Dynamic Product Selection', 'fluentform'),
126 + 'choice_label' => __('Enable Dynamic Product Selection', 'fluent-support'),
128 127 'input_label' => '',
129 - 'input_placeholder' => __('Set Product', 'fluentform')
128 + 'input_placeholder' => __('Set Product', 'fluent-support')
130 129 ],
131 130 'options' => $this->getProducts()
132 131 ],
133 132 [
@@ -132,62 +131,62 @@
132 131 ],
133 132 [
134 133 'key' => 'ticket_title',
135 134 'require_list' => false,
136 - 'label' => __('Ticket Title', 'fluentform'),
137 - 'placeholder' => __('Ticket Title', 'fluentform'),
135 + 'label' => __('Ticket Title', 'fluent-support'),
136 + 'placeholder' => __('Ticket Title', 'fluent-support'),
138 137 'component' => 'value_text'
139 138 ],
140 139 [
141 140 'key' => 'ticket_content',
142 141 'require_list' => false,
143 - 'label' => __('Ticket Content', 'fluentform'),
144 - 'placeholder' => __('Ticket Content', 'fluentform'),
142 + 'label' => __('Ticket Content', 'fluent-support'),
143 + 'placeholder' => __('Ticket Content', 'fluent-support'),
145 144 'component' => 'value_textarea'
146 145 ],
147 146 [
148 147 'key' => 'ticket_attachments',
149 148 'require_list' => false,
150 - 'label' => __('Ticket Attachments', 'fluentform'),
151 - 'Placeholder' => __('Ticket Attachments', 'fluentform'),
152 - 'tips' => __('Please input your file upload or image upload field shortcode here', 'fluentform'),
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'),
153 152 'component' => 'value_text'
154 153 ],
155 154 [
156 155 'key' => 'client_priority',
157 156 'require_list' => false,
158 - 'label' => __('Ticket Priority', 'fluentform'),
159 - 'Placeholder' => __('Ticket Priority', 'fluentform'),
160 - 'tips' => __('Make sure form field values match with Fluent Support priorities', 'fluentform'),
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'),
161 160 'component' => 'value_text'
162 161 ],
163 162 $this->getCustomField(), //Getting Fluent Support Custom Field To Map
164 163 [
165 164 'component' => 'html_info',
166 - '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</h4>', 'fluentform')
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>'
167 166 ],
168 167 [
169 168 'key' => 'CustomerFields',
170 169 'require_list' => false,
171 - 'label' => __('Customer Data', 'fluentform'),
172 - 'tips' => __('Please Map Your Customer Data for this form. If your customer already logged in you can leave this', 'fluentform'),
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'),
173 172 'component' => 'map_fields',
174 - 'field_label_remote' => __('Support Customer Field', 'fluentform'),
175 - 'field_label_local' => __('Form Field', 'fluentform'),
173 + 'field_label_remote' => __('Support Customer Field', 'fluent-support'),
174 + 'field_label_local' => __('Form Field', 'fluent-support'),
176 175 'primary_fileds' => [
177 176 [
178 177 'key' => 'email',
179 - 'label' => __('Email Address', 'fluentform'),
178 + 'label' => __('Email Address', 'fluent-support'),
180 179 'required' => true,
181 180 'input_options' => 'emails'
182 181 ],
183 182 [
184 183 'key' => 'first_name',
185 - 'label' => __('First Name', 'fluentform')
184 + 'label' => __('First Name', 'fluent-support')
186 185 ],
187 186 [
188 187 'key' => 'last_name',
189 - 'label' => __('Last Name', 'fluentform')
188 + 'label' => __('Last Name', 'fluent-support')
190 189 ]
191 190 ]
192 191 ],
193 192 [
@@ -192,12 +191,12 @@
192 191 ],
193 192 [
194 193 'key' => 'customer_other_fields',
195 194 'require_list' => false,
196 - 'label' => __('Customer Other Fields', 'fluentform'),
197 - 'tips' => 'Select which Fluent Forms fields pair with their<br /> respective Fluent Support fields.',
198 - 'field_label_remote' => __('Fluent Support Field', 'fluentform'),
199 - 'field_label_local' => __('Form Field', 'fluentform'),
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'),
200 199 'component' => 'dropdown_many_fields',
201 200 'options' => $fieldOptions
202 201 ],
203 202 ],
@@ -233,9 +232,9 @@
233 232
234 233 if(empty($customFields)){
235 234 return[
236 235 'component' => 'html_info',
237 - 'html_info' => __('', 'fluentform')
236 + 'html_info' => ''
238 237 ];
239 238 }
240 239
241 240 $fields = [];
@@ -246,9 +245,9 @@
246 245 }
247 246
248 247 $fields[] = [
249 248 'key' => $customFieldValue['slug'],
250 - 'label' => __($customFieldValue['label'], 'fluentform')
249 + 'label' => $customFieldValue['label']
251 250 ];
252 251 }
253 252
254 253 $fields = array_map('array_filter', $fields);
@@ -253,16 +252,16 @@
253 252
254 253 $fields = array_map('array_filter', $fields);
255 254 $fields = array_filter( $fields );
256 255
257 - return $customFieldsMapping = [
256 + return [
258 257 'key' => 'TicketCustomFields',
259 258 'require_list' => false,
260 - 'label' => __('Ticket Custom Fields', 'fluentform'),
261 - 'tips' => __('Please Map Your Ticket Custom Field Data for this form.', 'fluentform'),
259 + 'label' => __('Ticket Custom Fields', 'fluent-support'),
260 + 'tips' => __('Please Map Your Ticket Custom Field Data for this form.', 'fluent-support'),
262 261 'component' => 'map_fields',
263 - 'field_label_remote' => __('Fluent Support Custom Field', 'fluentform'),
264 - 'field_label_local' => __('Form Field', 'fluentform'),
262 + 'field_label_remote' => __('Fluent Support Custom Field', 'fluent-support'),
263 + 'field_label_local' => __('Form Field', 'fluent-support'),
265 264 'primary_fileds' => $fields
266 265 ];
267 266 }
268 267
@@ -274,9 +273,8 @@
274 273 public function notify($feed, $formData, $entry, $form)
275 274 {
276 275 $data = $feed['processedValues'];
277 276
278 -
279 277 if (!empty($data['email']) && !is_email($data['email'])) {
280 278 $data['email'] = Arr::get($formData, $data['email']);
281 279 }
282 280
@@ -283,25 +281,35 @@
283 281 $ticketCustomField = array_filter($data, function($key) {
284 282 return strpos($key, 'cf_') === 0;
285 283 }, ARRAY_FILTER_USE_KEY);
286 284
285 +
287 286 $customFields = apply_filters('fluent_support/ticket_custom_fields', []);
288 287
289 - foreach($customFields as $key=>$value){
290 - $type = [$key=>$value][$key]['type'];
291 - $slug = [$key=>$value][$key]['slug'];
292 - $type=='checkbox' && array_key_exists($slug, $ticketCustomField) ?
293 - $ticketCustomField[$slug] = explode(',', Arr::get($ticketCustomField, $slug)) : $ticketCustomField;
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 + }
294 301 }
295 302
296 303 $ticketData = [
297 304 'product_source' => 'local',
298 305 'mailbox_id' => Arr::get($data, 'list_id'),
299 - 'title' => sanitize_text_field(wp_unslash(Arr::get($data, 'ticket_title'))),
300 - 'content' => wp_unslash(wp_kses_post(Arr::get($data, 'ticket_content'))),
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')),
301 309 'attachments' => sanitize_text_field(Arr::get($data, 'ticket_attachments')),
302 - 'client_priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority'))),
303 - 'priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority'))),
310 + 'client_priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority', ''))),
311 + 'priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority', ''))),
304 312 'custom_fields' => $ticketCustomField,
305 313 'source' => 'web'
306 314 ];
307 315
@@ -332,12 +340,12 @@
332 340 $customerData['user_id'] = $user->ID;
333 341 }
334 342
335 343 if(empty($customerData['email'])) {
336 - do_action('ff_log_data', [
344 + do_action('fluentform/log_data', [
337 345 'title' => $feed['settings']['name'],
338 346 'status' => 'failed',
339 - 'description' => __('Support ticket creation failed, because no valid customer email found', 'fluentform'),
347 + 'description' => __('Support ticket creation failed, because no valid customer email found', 'fluent-support'),
340 348 'parent_source_id' => $form->id,
341 349 'source_id' => $entry->id,
342 350 'component' => $this->integrationKey,
343 351 'source_type' => 'submission_item'
@@ -348,8 +356,22 @@
348 356 $customerData['last_ip_address'] = $entry->ip;
349 357
350 358 $customer = Customer::maybeCreateCustomer($customerData);
351 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 +
352 374 $ticketData['customer_id'] = $customer->id;
353 375
354 376 $ticketData = apply_filters('fluent_support/create_ticket_data', $ticketData, $customer);
355 377 do_action('fluent_support/before_ticket_create', $ticketData, $customer);
@@ -357,17 +379,23 @@
357 379 $ticket = Ticket::create($ticketData);
358 380
359 381 if(defined('FLUENTSUPPORTPRO') && !empty($ticketData['custom_fields'])) {
360 382 $ticket->syncCustomFields($ticketData['custom_fields']);
361 - $ticket->custom_fields = $ticket->customData();
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();
362 389 }
363 390
364 391 do_action('fluent_support/ticket_created', $ticket, $customer);
365 392
366 - do_action('ff_log_data', [
393 + do_action('fluentform/log_data', [
367 394 'title' => $feed['settings']['name'],
368 395 'status' => 'success',
369 - 'description' => __('Support ticket has been created at Fluent Support. Ticket ID: '.$ticket->id, 'fluentform'),
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),
370 398 'parent_source_id' => $form->id,
371 399 'source_id' => $entry->id,
372 400 'component' => $this->integrationKey,
373 401 'source_type' => 'submission_item'
@@ -372,25 +400,69 @@
372 400 'component' => $this->integrationKey,
373 401 'source_type' => 'submission_item'
374 402 ]);
375 403
376 - if($ticketData['attachments']) {
377 - $attachments = explode(',', $ticketData['attachments']);
404 + if ($ticketData['attachments']) {
405 + $attachments = is_array($ticketData['attachments'])
406 + ? $ticketData['attachments']
407 + : explode(',', $ticketData['attachments']);
378 408
379 - foreach ($attachments as $attachment){
380 - $fileName = explode('/', $attachment);
381 - $fileName = end($fileName);
382 - Attachment::create(
383 - [
384 - 'ticket_id' => $ticket->id,
385 - 'file_path' => esc_url($attachment),
386 - 'full_url' => esc_url($attachment),
387 - 'title' => $fileName,
388 - 'person_id' => $customer->id
389 - ]
390 - );
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 + }
391 462 }
392 - $ticket->load($attachments);
463 +
464 + $ticket->load('attachments');
393 465 }
394 466
395 467 return true;
396 468 }
@@ -402,7 +474,19 @@
402 474
403 475 public function isEnabled()
404 476 {
405 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();
406 490 }
407 491
408 492 }