PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.1.0
Fluent Support – Helpdesk & Customer Support Ticket System v2.1.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 1.5.6 All 67 releases
fluent-support / app / Http / Controllers / SettingsController.php

SettingsController.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.1.0, at app/Http/Controllers/SettingsController.php

911 lines 34.1 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\Http\Controllers;
4
5
6 use FluentSupport\App\Models\MailBox;
7 use FluentSupport\App\Models\Meta;
8 use FluentSupport\App\Models\Product;
9 use FluentSupport\App\Services\EmailNotification\Settings;
10 use FluentSupport\App\Services\Helper;
11 use FluentSupport\Database\Migrations\AIActivityLogsMigrator;
12 use FluentSupport\Framework\Http\Request\Request;
13 use FluentSupport\App\Hooks\Handlers\ReCaptchaHandler;
14 use FluentSupport\Framework\Support\Arr;
15
16 /**
17 * SettingsController class is responsible for all settings
18 * This class is responsible for all request related to settings under global settings tab
19 * @package FluentSupport\App\Http\Controllers
20 *
21 * @version 1.0.0
22 */
23 class SettingsController extends Controller
24 {
25 /**
26 * getSettings method will return the settings by settings key
27 * @param Request $request
28 * @return array|array[]
29 */
30 public function getSettings(Request $request)
31 {
32 $settingsKey = $request->getSafe('settings_key', 'sanitize_text_field');
33
34 return (new Settings)->get($settingsKey);
35 }
36
37 /**
38 * getIntegrationSettings method will return the settings for integration
39 * @param Request $request
40 * @return array
41 */
42 public function getIntegrationSettings(Request $request)
43 {
44 $settings = Meta::where('object_type', 'integration_settings')->get();
45 $integrationSettings = [];
46 foreach ($settings as $index => $setting) {
47 $data = Helper::safeUnserialize($setting->value);
48 if (!empty($data['status']) && $data && $data['status'] == 'yes') {
49 $integrationSettings[] = $setting->key;
50 }
51 }
52 return $integrationSettings;
53 }
54
55 /**
56 * saveSettings method will save the requested settings data by setting key
57 * @param Request $request
58 * @return array
59 */
60 public function saveSettings(Request $request)
61 {
62 $settingsKey = $request->getSafe('settings_key', 'sanitize_text_field');
63 $settings = wp_unslash($request->get('settings', null));
64
65 // wp-editor fields: sanitize with wp_kses_post (same approach as Fluent Cart)
66 $htmlFields = ['login_message'];
67 $htmlValues = [];
68 if (is_array($settings)) {
69 foreach ($htmlFields as $field) {
70 if (isset($settings[$field])) {
71 $htmlValues[$field] = wp_kses_post($settings[$field]);
72 }
73 }
74 }
75
76 $settings = is_array($settings) ? map_deep($settings, 'sanitize_text_field') : [];
77
78 // Restore HTML fields
79 foreach ($htmlValues as $field => $value) {
80 $settings[$field] = $value;
81 }
82
83 (new Settings)->save($settingsKey, $settings);
84
85 return [
86 'message' => __('Settings has been updated', 'fluent-support')
87 ];
88 }
89
90 /**
91 * getPages method will return the list of pages created in WP
92 * @return array
93 */
94 public function getPages()
95 {
96 return [
97 'pages' => Helper::getWPPages()
98 ];
99 }
100
101 /**
102 * setupPortal method will setup the support portal
103 * @param Request $request
104 * @return array
105 * @throws \FluentSupport\Framework\Validator\ValidationException
106 */
107 public function setupPortal(Request $request)
108 {
109 $mailbox = $request->get('mailbox', null);
110 $mailbox = is_array($mailbox) ? [
111 'name' => isset($mailbox['name']) ? sanitize_text_field($mailbox['name']) : '',
112 'email' => isset($mailbox['email']) ? sanitize_email($mailbox['email']) : '',
113 'box_type' => isset($mailbox['box_type']) ? sanitize_key($mailbox['box_type']) : '',
114 'is_default' => isset($mailbox['is_default']) ? sanitize_text_field($mailbox['is_default']) : 'yes',
115 ] : [];
116
117 $this->validate($mailbox, [
118 'name' => 'required',
119 'email' => 'required|email',
120 'box_type' => 'required'
121 ]);
122
123 $settings = $request->get('global_settings', null);
124 $settings = is_array($settings) ? [
125 'create_portal_page' => isset($settings['create_portal_page']) ? sanitize_text_field($settings['create_portal_page']) : 'no',
126 'portal_page_id' => isset($settings['portal_page_id']) ? intval($settings['portal_page_id']) : 0,
127 ] : [];
128
129 $createPage = $settings['create_portal_page'] == 'yes';
130
131 if (!$createPage && empty($settings['portal_page_id'])) {
132 Helper::getSafeErrorMessage(new \Exception(__('Please select a page or enable create page', 'fluent-support')));
133 }
134
135 if ($createPage) {
136 // we have to create the page
137 $page_id = wp_insert_post(
138 array(
139 'comment_status' => 'close',
140 'ping_status' => 'close',
141 'post_author' => get_current_user_id(),
142 'post_title' => __('Support Portal', 'fluent-support'),
143 'post_status' => 'publish',
144 'post_content' => '<!-- wp:shortcode -->[fluent_support_portal]<!-- /wp:shortcode -->',
145 'post_type' => 'page'
146 )
147 );
148 } else {
149 $page_id = intval($settings['portal_page_id']);
150 }
151
152 $newMailBox = MailBox::first();
153 if (!$newMailBox) {
154 $mailbox['is_default'] = 'yes';
155 $mailbox['created_by'] = get_current_user_id();
156 $mailbox['settings']['admin_email_address'] = $mailbox['email'];
157 $newMailBox = MailBox::create($mailbox);
158 }
159
160 $settingsClass = new Settings();
161 $globalSettings = $settingsClass->globalBusinessSettings();
162
163 $globalSettings['portal_page_id'] = $page_id;
164
165 $settingsClass->save('global_business_settings', $globalSettings);
166
167
168 if (defined('WC_PLUGIN_FILE')) {
169 // URL Flash
170 flush_rewrite_rules(false);
171 }
172
173 return [
174 'mailbox' => $newMailBox,
175 'global_settings' => $globalSettings,
176 'mailboxes' => MailBox::select(['id', 'name', 'settings'])->get(),
177 'has_fluentform' => defined('FLUENTFORM')
178 ];
179
180 }
181
182 /**
183 * getFluentCRMSettings method will return the settings for Fluent CRM
184 * @param Request $request
185 * @return array
186 */
187 public function getFluentCRMSettings(Request $request)
188 {
189 if (defined('FLUENTCRM')) {
190 $settingDefault = [
191 'enabled' => 'no',
192 'default_status' => 'subscribed',
193 'assigned_list' => '',
194 'assigned_tags' => []
195 ];
196
197 $settings = Helper::getOption('_fluentcrm_intergration_settings');
198
199 $settings = wp_parse_args($settings, $settingDefault);
200
201 $settingsFields = [
202 'enabled' => [
203 'type' => 'inline-checkbox',
204 'true_label' => 'yes',
205 'false_label' => 'no',
206 'checkbox_label' => __('Enable FluentCRM Integration', 'fluent-support')
207 ],
208 'default_status' => [
209 'type' => 'input-radio',
210 'label' => __('Default status for new contacts', 'fluent-support'),
211 'options' => [
212 [
213 'id' => 'subscribed',
214 'label' => __('Subscribed', 'fluent-support')
215 ],
216 [
217 'id' => 'pending',
218 'label' => __('Pending', 'fluent-support')
219 ]
220 ],
221 'dependency' => [
222 'depends_on' => 'enabled',
223 'operator' => '=',
224 'value' => 'yes'
225 ],
226 'inline_help' => __('Select the default status for new contacts. If you select pending and it\'s a new contact then a double optin email will be sent', 'fluent-support')
227 ],
228 'assigned_list' => [
229 'type' => 'input-options',
230 'label' => __('Add to FluentCRM list (optional)', 'fluent-support'),
231 'options' => \FluentCrm\App\Models\Lists::select(['id', 'title'])->orderBy('title', 'ASC')->get(),
232 'dependency' => [
233 'depends_on' => 'enabled',
234 'operator' => '=',
235 'value' => 'yes'
236 ],
237 ],
238 'assigned_tags' => [
239 'type' => 'input-options',
240 'multiple' => true,
241 'label' => __('Add to Tags', 'fluent-support'),
242 'options' => \FluentCrm\App\Models\Tag::select(['id', 'title'])->orderBy('title', 'ASC')->get(),
243 'dependency' => [
244 'depends_on' => 'enabled',
245 'operator' => '=',
246 'value' => 'yes'
247 ]
248 ]
249 ];
250
251 return [
252 'is_installed' => true,
253 'settings' => $settings,
254 'settings_fields' => $settingsFields,
255 'fluentcrm_logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/fluentcrm-logo.svg'
256 ];
257 }
258
259 return [
260 'is_installed' => false,
261 'fluentcrm_logo' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/fluentcrm-logo.svg'
262 ];
263
264 }
265
266 public function setupInstallation(Request $request)
267 {
268 $installFluentForm = $request->getSafe('install_fluentform', 'sanitize_text_field', 'no');
269
270 if ($installFluentForm == 'yes' && !defined('FLUENTFORM')) {
271 $this->installFluentForm();
272 }
273
274 $optinEmail = $request->getSafe('optin_email', 'sanitize_email', '');
275 if ($optinEmail && is_email($optinEmail)) {
276 $this->shareEmail($optinEmail);
277 }
278
279 $shareEssential = $request->getSafe('share_essentials', 'sanitize_text_field', 'no');
280 if ($shareEssential == 'yes') {
281 Helper::updateOption('_share_essential', $shareEssential);
282 }
283
284 return $this->sendSuccess([
285 'message' => __('Installation has been completed', 'fluent-support')
286 ]);
287
288 }
289
290 public function saveReCaptchaSettings(Request $request)
291 {
292 $data = $request->get('reCaptcha');
293
294 if (is_string($data) && 'clear-reCaptcha-settings' === sanitize_text_field($data)) {
295 if (Meta::where('object_type', '_fs_recaptcha_settings')->delete()) {
296 return $this->sendSuccess([
297 'message' => __('Your reCAPTCHA settings deleted successfully.', 'fluent-support'),
298 ]);
299 }
300
301 return $this->sendError([
302 'message' => __('Unable to delete reCAPTCHA settings, try again', 'fluent-support'),
303 ]);
304 }
305
306 if (!is_array($data)) {
307 return $this->sendError([
308 'message' => __('Invalid reCAPTCHA data.', 'fluent-support'),
309 ]);
310 }
311
312 $reCaptchaData = [
313 'reCaptcha_version' => sanitize_text_field($data['reCaptchaVersion'] ?? ''),
314 'siteKey' => sanitize_text_field($data['siteKey'] ?? ''),
315 'secretKey' => sanitize_text_field($data['secretKey'] ?? ''),
316 'formContainingReCaptcha' => array_map('sanitize_text_field', (array) ($data['formContainingReCaptcha'] ?? [])),
317 'is_enabled' => sanitize_text_field($data['reCaptchaEnabled'] ?? 'no'),
318 ];
319
320 $previousValue = Meta::where('object_type', '_fs_recaptcha_settings')->first();
321
322 if ($previousValue === $reCaptchaData) {
323 return $this->sendError([
324 'message' => __('Your recaptcha details are already saved.', 'fluent-support'),
325 ]);
326 }
327
328 $captchaResponse = sanitize_text_field($data['captchaResponse'] ?? '');
329
330 if ($captchaResponse) {
331 $verifyReCaptcha = ReCaptchaHandler::validateRecaptcha($captchaResponse, $reCaptchaData['secretKey'], $reCaptchaData['reCaptcha_version']);
332
333 if (!$verifyReCaptcha) {
334 return $this->sendError([
335 'message' => __('Your reCAPTCHA settings are not valid.', 'fluent-support'),
336 ]);
337 }
338 } elseif (!$previousValue) {
339 return $this->sendError([
340 'message' => __('Please verify reCAPTCHA before saving.', 'fluent-support'),
341 ]);
342 }
343
344 if ($previousValue) {
345 Meta::where('object_type', '_fs_recaptcha_settings')->update([
346 'value' => maybe_serialize($reCaptchaData)
347 ]);
348 return $this->sendSuccess([
349 'message' => __('Your reCAPTCHA settings updated successfully.', 'fluent-support'),
350 ]);
351 } else {
352 Meta::insert([
353 'object_type' => '_fs_recaptcha_settings',
354 'key' => '_fs_recaptcha_data',
355 'value' => maybe_serialize($reCaptchaData)
356 ]);
357 }
358
359 return $this->sendSuccess([
360 'message' => __('Your reCAPTCHA settings added successfully.', 'fluent-support'),
361 ]);
362 }
363
364 public function saveOpenAISettings(Request $request)
365 {
366 $data = [
367 'api_key' => $request->getSafe('api_key', 'sanitize_text_field', ''),
368 'model' => $request->getSafe('model', 'sanitize_text_field', ''),
369 ];
370
371 $response = Helper::authorizeChatGPTAPIKey($data);
372
373 if (is_wp_error($response)) {
374 return $this->sendError([
375 'message' => __('There was an error verifying the API key.', 'fluent-support'),
376 ]);
377 }
378
379 $body = json_decode(wp_remote_retrieve_body($response), true);
380
381 if (isset($body['error'])) {
382 return $this->sendError([
383 'message' => __('Invalid API key. Please provide a valid ChatGPT API key.', 'fluent-support'),
384 ]);
385 }
386
387 try {
388 $isDataSaved = Helper::saveOpenAIData('_fs_openai_settings', '_fs_openai_data', $data);
389 if ($isDataSaved) {
390 AIActivityLogsMigrator::migrate();
391 }
392 return $this->sendSuccess([
393 'message' => __('OpenAI settings have been successfully saved.', 'fluent-support'),
394 ]);
395 } catch (\Exception $e) {
396 // translators: %s is the error message from the exception
397 $translatedMessage = __('An error occurred while saving the settings: %s', 'fluent-support');
398 $errorMessage = sprintf($translatedMessage, Helper::getSafeErrorMessage($e));
399
400 return $this->sendError([
401 'message' => $errorMessage,
402 ]);
403 }
404 }
405
406
407 public function disconnectOpenAI()
408 {
409 $deletedRecords = Meta::where([
410 'object_type' => '_fs_openai_settings',
411 'key' => '_fs_openai_data',
412 ])->delete();
413
414 if ($deletedRecords) {
415 return $this->sendSuccess([
416 'message' => __('OpenAI settings have been successfully disconnected.', 'fluent-support'),
417 ]);
418 } else {
419 return $this->sendError([
420 'message' => __('Failed to disconnect OpenAI settings. No matching records found or an error occurred.', 'fluent-support'),
421 ]);
422 }
423 }
424
425 public function getOpenAISettings()
426 {
427 $modelOptions = $this->getOpenAIModelOptions();
428 $supportedModels = array_column($modelOptions, 'value');
429
430 $settings = [
431 'api_key' => '',
432 'model' => 'gpt-5.2',
433 ];
434
435 $chatGPTSettingsData = Meta::where('object_type', '_fs_openai_settings')->first();
436 if ($chatGPTSettingsData) {
437 $settings = Helper::safeUnserialize($chatGPTSettingsData->value);
438
439 if (!empty($settings['model']) && !in_array($settings['model'], $supportedModels, true)) {
440 $previousModel = $settings['model'];
441 $settings['model'] = 'gpt-5.2';
442 Helper::saveOpenAIData('_fs_openai_settings', '_fs_openai_data', $settings);
443 $settings['previous_model'] = $previousModel;
444 $settings['model_migrated'] = true;
445 }
446 }
447
448 $settings['model_options'] = $modelOptions;
449
450 return $this->sendSuccess($settings);
451 }
452
453 private function getOpenAIModelOptions()
454 {
455 $models = [
456 ['value' => 'gpt-5.2', 'label' => 'GPT-5.2'],
457 ['value' => 'gpt-5.2-chat-latest', 'label' => 'GPT-5.2 Chat'],
458 ['value' => 'gpt-4.1', 'label' => 'GPT-4.1'],
459 ['value' => 'gpt-4.1-mini', 'label' => 'GPT-4.1 Mini'],
460 ['value' => 'gpt-4.1-nano', 'label' => 'GPT-4.1 Nano'],
461 ['value' => 'gpt-4o', 'label' => 'GPT-4o'],
462 ['value' => 'gpt-4o-mini', 'label' => 'GPT-4o Mini'],
463 ['value' => 'gpt-4o-2024-08-06', 'label' => 'GPT-4o (2024-08-06)'],
464 ['value' => 'gpt-4o-2024-05-13', 'label' => 'GPT-4o (2024-05-13)'],
465 ['value' => 'gpt-4o-mini-2024-07-18', 'label' => 'GPT-4o Mini (2024-07-18)'],
466 ['value' => 'gpt-4-turbo', 'label' => 'GPT-4 Turbo'],
467 ['value' => 'gpt-4-turbo-2024-04-09', 'label' => 'GPT-4 Turbo (2024-04-09)'],
468 ['value' => 'gpt-4-turbo-preview', 'label' => 'GPT-4 Turbo Preview'],
469 ['value' => 'gpt-4', 'label' => 'GPT-4'],
470 ['value' => 'gpt-4-0613', 'label' => 'GPT-4 (0613)'],
471 ['value' => 'gpt-3.5-turbo', 'label' => 'GPT-3.5 Turbo'],
472 ['value' => 'gpt-3.5-turbo-0125', 'label' => 'GPT-3.5 Turbo (0125)'],
473 ['value' => 'o3', 'label' => 'o3'],
474 ['value' => 'o3-mini', 'label' => 'o3-mini'],
475 ['value' => 'o4-mini', 'label' => 'o4-mini'],
476 ['value' => 'o1', 'label' => 'o1'],
477 ['value' => 'gpt-4-0314', 'label' => 'GPT-4 (0314) - Deprecated soon'],
478 ['value' => 'gpt-4-1106-preview', 'label' => 'GPT-4 (1106 Preview) - Deprecated soon'],
479 ['value' => 'gpt-4-0125-preview', 'label' => 'GPT-4 (0125 Preview) - Deprecated soon'],
480 ];
481
482 return apply_filters('fluent_support/supported_openai_models', $models);
483 }
484
485 public function getReCaptchaSettings()
486 {
487 $reCaptchaSettingsData = Meta::where('object_type', '_fs_recaptcha_settings')->first();
488 if ($reCaptchaSettingsData) {
489 $settings = Helper::safeUnserialize($reCaptchaSettingsData->value);
490 return $this->sendSuccess($settings);
491 }
492
493 return [];
494 }
495
496 private function shareEmail($optinEmail)
497 {
498 $user = get_user_by('ID', get_current_user_id());
499 $data = [
500 'answers' => [
501 'website' => site_url(),
502 'email' => $optinEmail,
503 'first_name' => $user->first_name,
504 'last_name' => $user->last_name,
505 'name' => $user->display_name,
506 'has_fluentform' => defined('FLUENTFORM') ? 'yes' : 'no'
507 ],
508 'questions' => [
509 'website' => 'website',
510 'first_name' => 'first_name',
511 'last_name' => 'last_name',
512 'email' => 'email',
513 'name' => 'name',
514 'has_fluentform' => 'has_fluentform'
515 ],
516 'user' => [
517 'email' => $optinEmail
518 ],
519 'fb_capture' => 1,
520 'form_id' => 77
521 ];
522
523 $url = add_query_arg($data, 'https://wpmanageninja.com/');
524
525 wp_remote_post($url, [
526 'sslverify' => false
527 ]);
528 }
529
530 /**
531 * installFluentCRM method will install Fluent CRM plugin
532 * @return array
533 */
534 public function installFluentCRM()
535 {
536
537 if (defined('FLUENTCRM')) {
538 return [
539 'is_installed' => true,
540 'message' => __('FluentCRM plugin has been installed and activated successfully', 'fluent-support')
541 ];
542 }
543
544 if (!current_user_can('install_plugins')) {
545 return $this->sendError([
546 'message' => __('Sorry! you do not have permission to install plugin', 'fluent-support')
547 ]);
548 }
549
550 $plugin_id = 'fluent-crm';
551 $plugin = [
552 'name' => 'Fluent CRM',
553 'repo-slug' => 'fluent-crm',
554 'file' => 'fluent-crm.php',
555 ];
556
557 $this->backgroundInstaller($plugin, $plugin_id);
558
559 if (defined('FLUENTCRM')) {
560 return [
561 'is_installed' => true,
562 'message' => __('FluentCRM plugin has been installed and activated successfully', 'fluent-support')
563 ];
564 } else {
565 return $this->sendError([
566 'message' => __('Sorry! FluentCRM could not be installed. Please install manually', 'fluent-support')
567 ]);
568 }
569 }
570
571 public function installFluentForm()
572 {
573
574 if (defined('FLUENTFORM')) {
575 return [
576 'is_installed' => true,
577 'message' => __('Fluent Forms plugin has been installed and activated successfully', 'fluent-support')
578 ];
579 }
580
581 if (!current_user_can('install_plugins')) {
582 return $this->sendError([
583 'message' => __('Sorry! you do not have permission to install plugin', 'fluent-support')
584 ]);
585 }
586
587 $plugin_id = 'fluentform';
588 $plugin = [
589 'name' => 'Fluent Forms',
590 'repo-slug' => 'fluentform',
591 'file' => 'fluentform.php',
592 ];
593
594 $this->backgroundInstaller($plugin, $plugin_id);
595
596 if (defined('FLUENTFORM')) {
597 return [
598 'is_installed' => true,
599 'message' => __('Fluent Forms plugin has been installed and activated successfully', 'fluent-support')
600 ];
601 } else {
602 return [
603 'is_installed' => false,
604 'message' => __('Fluent Forms could not be installed', 'fluent-support')
605 ];
606 }
607 }
608
609 private function backgroundInstaller($plugin_to_install, $plugin_id)
610 {
611 if (!empty($plugin_to_install['repo-slug'])) {
612 require_once ABSPATH . 'wp-admin/includes/file.php';
613 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
614 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
615 require_once ABSPATH . 'wp-admin/includes/plugin.php';
616
617 WP_Filesystem();
618
619 $skin = new \Automatic_Upgrader_Skin();
620 $upgrader = new \WP_Upgrader($skin);
621 $installed_plugins = array_reduce(array_keys(\get_plugins()), array($this, 'associate_plugin_file'), array());
622 $plugin_slug = $plugin_to_install['repo-slug'];
623 $plugin_file = isset($plugin_to_install['file']) ? $plugin_to_install['file'] : $plugin_slug . '.php';
624 $installed = false;
625 $activate = false;
626
627 // See if the plugin is installed already.
628 if (isset($installed_plugins[$plugin_file])) {
629 $installed = true;
630 $activate = !is_plugin_active($installed_plugins[$plugin_file]);
631 }
632
633 // Install this thing!
634 if (!$installed) {
635 // Suppress feedback.
636 ob_start();
637
638 try {
639 $plugin_information = plugins_api(
640 'plugin_information',
641 array(
642 'slug' => $plugin_slug,
643 'fields' => array(
644 'short_description' => false,
645 'sections' => false,
646 'requires' => false,
647 'rating' => false,
648 'ratings' => false,
649 'downloaded' => false,
650 'last_updated' => false,
651 'added' => false,
652 'tags' => false,
653 'homepage' => false,
654 'donate_link' => false,
655 'author_profile' => false,
656 'author' => false,
657 ),
658 )
659 );
660
661 if (is_wp_error($plugin_information)) {
662 throw new \Exception($plugin_information->get_error_message());
663 }
664
665 $package = $plugin_information->download_link;
666 $download = $upgrader->download_package($package);
667
668 if (is_wp_error($download)) {
669 throw new \Exception($download->get_error_message());
670 }
671
672 $working_dir = $upgrader->unpack_package($download, true);
673
674 if (is_wp_error($working_dir)) {
675 throw new \Exception($working_dir->get_error_message());
676 }
677
678 $result = $upgrader->install_package(
679 array(
680 'source' => $working_dir,
681 'destination' => WP_PLUGIN_DIR,
682 'clear_destination' => false,
683 'abort_if_destination_exists' => false,
684 'clear_working' => true,
685 'hook_extra' => array(
686 'type' => 'plugin',
687 'action' => 'install',
688 ),
689 )
690 );
691
692 if (is_wp_error($result)) {
693 throw new \Exception($result->get_error_message());
694 }
695
696 $activate = true;
697
698 } catch (\Exception $e) {
699 }
700
701 // Discard feedback.
702 ob_end_clean();
703 }
704
705 wp_clean_plugins_cache();
706
707 // Activate this thing.
708 if ($activate) {
709 try {
710 $result = activate_plugin($installed ? $installed_plugins[$plugin_file] : $plugin_slug . '/' . $plugin_file);
711
712 if (is_wp_error($result)) {
713 throw new \Exception($result->get_error_message());
714 }
715 } catch (\Exception $e) {
716 }
717 }
718 }
719 }
720
721 private function associate_plugin_file($plugins, $key)
722 {
723 $path = explode('/', $key);
724 $filename = end($path);
725 $plugins[$filename] = $key;
726 return $plugins;
727 }
728
729 public function getRemoteUploadSettings(Request $request)
730 {
731 $dropBoxConfigured = false;
732 $googleDriveConfigured = false;
733 $cloudflareR2Configured = false;
734 $amazonS3Configured = false;
735
736 if (defined('FLUENTSUPPORTPRO')) {
737 $dropBoxSettings = Helper::getIntegrationOption('dropbox_settings');
738 $dropBoxConfigured = $dropBoxSettings && !empty($dropBoxSettings['access_token']);
739
740 $googleDriveSettings = Helper::getIntegrationOption('google_drive_settings');
741 $googleDriveConfigured = $googleDriveSettings && !empty($googleDriveSettings['access_token']);
742
743 $cloudflareR2Settings = Helper::getIntegrationOption('cloudflare_r2_settings');
744 $cloudflareR2Configured = $cloudflareR2Settings && !empty($cloudflareR2Settings['secret_access_key']) && Arr::get($cloudflareR2Settings, 'status') == 'yes';
745
746 $amazonS3Settings = Helper::getIntegrationOption('amazon_s3_settings');
747 $amazonS3Configured = $amazonS3Settings && !empty($amazonS3Settings['secret_access_key']) && Arr::get($amazonS3Settings, 'status') == 'yes';
748 }
749
750 $drivers = apply_filters('fluent_support/storage_drivers_info', [
751 'local' => [
752 'title' => 'Default WordPress Storage',
753 'is_disabled' => false,
754 'is_configured' => true,
755 'icon' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/folder.svg',
756 'description' => __('Upload and store the files to your WordPress File System Storage.', 'fluent-support')
757 ],
758 'dropbox' => [
759 'meta_key' => 'dropbox_settings',
760 'title' => 'Dropbox',
761 'has_config' => true,
762 'is_configured' => $dropBoxConfigured,
763 'require_pro' => !defined('FLUENTSUPPORTPRO'),
764 'icon' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/dbox.svg',
765 'description' => __('Upload and store the files to your Dropbox Storage.', 'fluent-support')
766 ],
767 'google_drive' => [
768 'meta_key' => 'google_drive_settings',
769 'title' => 'Google Drive',
770 'has_config' => true,
771 'is_configured' => $googleDriveConfigured,
772 'require_pro' => !defined('FLUENTSUPPORTPRO'),
773 'upgrade_url' => 'https://fluentsupport.com/pricing',
774 'description' => __('Upload and store the files to your Google Drive Storage.', 'fluent-support'),
775 'icon' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/drive.svg',
776 ],
777 'cloudflare_r2' => [
778 'meta_key' => 'cloudflare_r2_settings',
779 'title' => 'Cloudflare R2',
780 'has_config' => true,
781 'is_configured' => $cloudflareR2Configured,
782 'require_pro' => !defined('FLUENTSUPPORTPRO'),
783 'upgrade_url' => 'https://fluentsupport.com/pricing',
784 'description' => __('Upload and store the files to Cloudflare R2 Storage with zero egress fees.', 'fluent-support'),
785 'icon' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/cloudflare-r2.svg',
786 ],
787 'amazon_s3' => [
788 'meta_key' => 'amazon_s3_settings',
789 'title' => 'Amazon S3',
790 'has_config' => true,
791 'is_configured' => $amazonS3Configured,
792 'require_pro' => !defined('FLUENTSUPPORTPRO'),
793 'upgrade_url' => 'https://fluentsupport.com/pricing',
794 'description' => __('Upload and store the files to Amazon S3 cloud storage.', 'fluent-support'),
795 'icon' => FLUENT_SUPPORT_PLUGIN_URL . 'assets/images/icons/amazon-s3.svg',
796 ]
797 ]);
798
799 return [
800 'drivers' => $drivers,
801 'enabled_driver' => Helper::getUploadDriverKey()
802 ];
803 }
804
805 public function updateRemoteUploadDriver(Request $request)
806 {
807 $driver = $request->getSafe('driver', 'sanitize_text_field');
808 Helper::updateOption('file_upload_driver', $driver);
809
810 return [
811 'message' => 'Upload driver has been updated successfully',
812 'driver' => $driver
813 ];
814 }
815
816 /**
817 * getIntegrationLogs method will return the integration logs
818 * @return array
819 */
820 public function integrationStatuses()
821 {
822 return [
823 'connections' => Helper::getIntegrationStatuses()
824 ];
825 }
826
827 public function getSettingsMenu()
828 {
829 return Helper::getGlobalSettingsMenu();
830 }
831
832 public function getFluentBotSettings()
833 {
834 $meta = Meta::where([
835 'object_type' => 'fluent_bot_settings',
836 'object_id' => 1,
837 'key' => '_fs_fluent_bot_config'
838 ])->first();
839
840 $settings = $meta ? Helper::safeUnserialize($meta->value) : [];
841
842 $productItems = Product::all()->map(function ($product) {
843 return [
844 'id' => $product->id,
845 'title' => $product->title
846 ];
847 })->values()->all();
848
849 return array_merge([
850 'generalApiKey' => '',
851 'generalBotId' => '',
852 'isEnabled' => false,
853 'productMappings' => [],
854 'products' => $productItems
855 ], $settings, [
856 'products' => $productItems
857 ]);
858 }
859
860 public function saveFluentBotSettings(Request $request)
861 {
862 $data = [
863 'generalBotId' => $request->getSafe('generalBotId', 'sanitize_text_field'),
864 'isEnabled' => $request->getSafe('isEnabled', 'rest_sanitize_boolean'),
865 'productMappings' => []
866 ];
867
868 $productMappings = (array) $request->get('productMappings', []);
869
870 foreach ($productMappings as $mapping) {
871 if (!is_array($mapping)) {
872 continue;
873 }
874
875 $data['productMappings'][] = [
876 'productId' => intval($mapping['productId'] ?? 0),
877 'productTitle' => sanitize_text_field($mapping['productTitle'] ?? ''),
878 'botId' => sanitize_text_field($mapping['botId'] ?? ''),
879 ];
880 }
881
882 $serialized = maybe_serialize($data);
883
884 $existing = Meta::where([
885 'object_type' => 'fluent_bot_settings',
886 'object_id' => 1,
887 'key' => '_fs_fluent_bot_config'
888 ])->first();
889
890 if ($existing) {
891 $existing->update(['value' => $serialized]);
892 } else {
893 Meta::create([
894 'object_type' => 'fluent_bot_settings',
895 'object_id' => 1,
896 'key' => '_fs_fluent_bot_config',
897 'value' => $serialized
898 ]);
899
900 AIActivityLogsMigrator::migrate();
901 }
902
903 return [
904 'success' => true,
905 'message' => 'Settings saved successfully',
906 'data' => $data
907 ];
908 }
909
910 }
911