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
fluent-support / app / Hooks / CLI / FluentCli.php

FluentCli.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.4.5, at app/Hooks/CLI/FluentCli.php

349 lines 12.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\Hooks\CLI;
4
5 use FluentSupport\App\Modules\StatModule;
6 use FluentSupport\App\Services\Tickets\Importer\MigratorService;
7 use FluentSupport\App\Models\Meta;
8
9 class FluentCli
10 {
11 private $domain;
12 private $accessToken;
13
14 public function stats($args, $assoc_args)
15 {
16 $overallStats = StatModule::getOverAllStats();
17 $format = \WP_CLI\Utils\get_flag_value($assoc_args, 'format', 'table');
18
19 \WP_CLI\Utils\format_items(
20 $format,
21 $overallStats,
22 ['title', 'count']
23 );
24 }
25
26 public function activate_license($args, $assoc_args)
27 {
28 if (empty($assoc_args['key'])) {
29 \WP_CLI::line('use --key=LICENSE_KEY to activate the license');
30 return;
31 }
32
33 $licenseKey = trim(sanitize_text_field($assoc_args['key'] ?? ''));
34
35 if (!class_exists('\FluentSupportPro\App\Services\PluginManager\LicenseManager')) {
36 \WP_CLI::line('FluentSupport Pro is required');
37 return;
38 }
39
40 \WP_CLI::line('Validating License, Please wait');
41
42 $licenseManager = new \FluentSupportPro\App\Services\PluginManager\LicenseManager();
43 $response = $licenseManager->activateLicense($licenseKey);
44
45 if (is_wp_error($response)) {
46 \WP_CLI::error($response->get_error_message());
47 return;
48 }
49
50 \WP_CLI::line('Your license key has been successfully updated');
51 \WP_CLI::line('Your License Status: ' . $response['status']);
52 \WP_CLI::line('Expire Date: ' . $response['expires']);
53 return;
54 }
55
56 public function license_status()
57 {
58
59 if (!class_exists('\FluentSupportPro\App\Services\PluginManager\LicenseManager')) {
60 \WP_CLI::line('FluentSupport Pro is required');
61 return;
62 }
63
64 \WP_CLI::line('Fetching License details, Please wait');
65
66 $licenseManager = new \FluentSupportPro\App\Services\PluginManager\LicenseManager();
67 $licenseManager->verifyRemoteLicense(true);
68 $response = $licenseManager->getLicenseDetails();
69
70 \WP_CLI::line('Your License Status: ' . $response['status']);
71 \WP_CLI::line('Expires: ' . $response['expires']);
72 return;
73 }
74
75 public function freshdesk_ticket_import($args, $assoc_args)
76 {
77 try {
78 if (!defined('FLUENTSUPPORTPRO_PLUGIN_VERSION')) {
79 \WP_CLI::error('Fluent Support Pro is required for this command.');
80 return;
81 }
82
83 if (!$this->validateAndExtractParams($assoc_args)) {
84 return;
85 }
86
87 $startPage = $this->checkPreviousMigration();
88
89 $this->processMigration($startPage);
90
91 } finally {
92 $this->domain = null;
93 $this->accessToken = null;
94 }
95 }
96
97 /**
98 * Validates and extracts parameters from CLI arguments.
99 *
100 * @param array $assoc_args Associative array of options.
101 * @return bool True if validation succeeded, false otherwise
102 */
103 private function validateAndExtractParams($assoc_args)
104 {
105 $this->domain = \WP_CLI\Utils\get_flag_value($assoc_args, 'domain');
106 if (empty($this->domain)) {
107 $this->domain = \cli\prompt('Enter your support domain (e.g. https://yourcompany.freshdesk.com)');
108 }
109
110 $this->accessToken = \WP_CLI\Utils\get_flag_value($assoc_args, 'access_token');
111 if (empty($this->accessToken)) {
112 $this->accessToken = \cli\prompt('Enter your access token');
113 }
114
115 if (empty($this->accessToken) || empty($this->domain)) {
116 \WP_CLI::error('Both domain and access token are required to proceed.');
117 return false;
118 }
119
120 return true;
121 }
122
123 /**
124 * Check for previous migration data and determine the starting page.
125 *
126 * @param string $metaKey The object_type key in fs_meta. Defaults to Freshdesk.
127 * @param string|null $identifier The domain or other unique identifier. Defaults to $this->domain.
128 * @return int Page number to start from
129 */
130 private function checkPreviousMigration($metaKey = '_fs_freshdesk_migration_info', $identifier = null)
131 {
132 if ($identifier === null) {
133 $identifier = $this->domain;
134 }
135
136 $metadata = Meta::where('object_type', $metaKey)->first();
137
138 if (empty($metadata)) {
139 return 1;
140 }
141
142 $previouslyImported = maybe_unserialize($metadata->value ?? []);
143 $previousDomain = $metadata->key ?? '';
144
145 if ($previousDomain === $identifier &&
146 !empty($previouslyImported['has_more']) &&
147 $previouslyImported['has_more'] === true &&
148 !empty($previouslyImported['next_page'])) {
149
150 \WP_CLI::line("A previous incomplete migration was found for this domain:");
151 \WP_CLI::line(" - Last imported page: " . ($previouslyImported['imported_page'] ?? 'N/A'));
152 \WP_CLI::line(" - Tickets imported so far: " . ($previouslyImported['completed'] ?? 0));
153
154 $choice = \cli\prompt('Do you want to resume from the last incomplete page? (yes/no)', 'yes');
155
156 if (strtolower($choice) === 'yes') {
157 $startPage = (int) $previouslyImported['next_page'];
158 \WP_CLI::line("Resuming from page $startPage...");
159 return $startPage;
160 }
161
162 \WP_CLI::line("Starting over from page 1...");
163 }
164
165 return 1;
166 }
167
168 /**
169 * Import tickets page by page until the provider reports no more.
170 *
171 * @param int $startPage Page number to start from
172 * @param string $provider Handler name passed to MigratorService. Defaults to 'freshdesk'.
173 * @param array $query Credentials and pagination state. Defaults to Freshdesk class props.
174 */
175 private function processMigration($startPage = 1, $provider = 'freshdesk', $query = null)
176 {
177 try {
178 if ($query === null) {
179 $query = [
180 'access_token' => $this->accessToken,
181 'domain' => $this->domain,
182 ];
183 }
184
185 $page = $startPage;
186 $migrator = new MigratorService;
187 $totalImported = 0;
188 $totalSkipped = 0;
189
190 while (true) {
191 \WP_CLI::line("Processing page: $page");
192
193 $result = $migrator->handleImport($page, $provider, $query);
194
195 if (empty($result) || !isset($result['completed'])) {
196 \WP_CLI::warning("Invalid response received for page $page. Stopping migration.");
197 break;
198 }
199
200 // Cursor-based providers (Zendesk) need these carried into the next request.
201 if (array_key_exists('cursor', $result)) {
202 $query['cursor'] = $result['cursor'];
203 }
204 if (array_key_exists('next_page_url', $result)) {
205 $query['next_page_url'] = $result['next_page_url'];
206 }
207
208 if (!empty($result['error'])) {
209 \WP_CLI::error("Migration error: " . ($result['message'] ?? 'Unknown error'));
210 break;
211 }
212
213 $imported = count($result['insert_ids'] ?? []);
214 $skipped = intval($result['skips'] ?? 0);
215
216 $totalImported += $imported;
217 $totalSkipped += $skipped;
218
219 \WP_CLI::success(sprintf(
220 "Page %d processed: %d ticket(s) imported, %d skipped",
221 $page,
222 $imported,
223 $skipped
224 ));
225
226 if (empty($result['has_more'])) {
227 break;
228 }
229
230 $page = intval($result['next_page'] ?? ($page + 1));
231 }
232
233 \WP_CLI::success(sprintf(
234 "Migration complete. Total: %d imported, %d skipped.",
235 $totalImported,
236 $totalSkipped
237 ));
238 } catch (\Exception $e) {
239 \WP_CLI::error("Migration failed: " . $e->getMessage());
240 }
241 }
242
243 // -------------------------------------------------------------------------
244 // Zendesk
245 // -------------------------------------------------------------------------
246
247 public function zendesk_ticket_import($args, $assoc_args)
248 {
249 try {
250 if (!defined('FLUENTSUPPORTPRO_PLUGIN_VERSION')) {
251 \WP_CLI::error('Fluent Support Pro is required for this command.');
252 return;
253 }
254
255 $this->domain = \WP_CLI\Utils\get_flag_value($assoc_args, 'domain');
256 if (empty($this->domain)) {
257 $this->domain = \cli\prompt('Enter your Zendesk domain (e.g. https://yourcompany.zendesk.com)');
258 }
259
260 $email = \WP_CLI\Utils\get_flag_value($assoc_args, 'email');
261 if (empty($email)) {
262 $email = \cli\prompt('Enter your Zendesk admin email');
263 }
264
265 $this->accessToken = \WP_CLI\Utils\get_flag_value($assoc_args, 'access_token');
266 if (empty($this->accessToken)) {
267 $this->accessToken = \cli\prompt('Enter your API token');
268 }
269
270 if (empty($this->domain) || empty($email) || empty($this->accessToken)) {
271 \WP_CLI::error('Domain, email, and access token are all required to proceed.');
272 return;
273 }
274
275 $includeArchived = \WP_CLI\Utils\get_flag_value($assoc_args, 'include_archived', false);
276
277 $startPage = $this->checkPreviousMigration('_fs_zendesk_migration_info', $this->domain);
278
279 $query = [
280 'access_token' => $this->accessToken,
281 'domain' => $this->domain,
282 'email' => $email,
283 'include_archived' => $includeArchived,
284 ];
285
286 // On resume, restore cursor state saved by the previous run
287 if ($startPage > 1) {
288 $savedProgress = Meta::where('object_type', '_fs_zendesk_migration_info')->first();
289 if ($savedProgress) {
290 $savedData = maybe_unserialize($savedProgress->value ?? []);
291 if (!empty($savedData['cursor'])) {
292 $query['cursor'] = $savedData['cursor'];
293 }
294 if (!empty($savedData['next_page_url'])) {
295 $query['next_page_url'] = $savedData['next_page_url'];
296 }
297 }
298 }
299
300 $this->processMigration($startPage, 'zendesk', $query);
301
302 } finally {
303 $this->domain = null;
304 $this->accessToken = null;
305 }
306 }
307
308 // -------------------------------------------------------------------------
309 // HelpScout
310 // -------------------------------------------------------------------------
311
312 public function helpscout_ticket_import($args, $assoc_args)
313 {
314 try {
315 if (!defined('FLUENTSUPPORTPRO_PLUGIN_VERSION')) {
316 \WP_CLI::error('Fluent Support Pro is required for this command.');
317 return;
318 }
319
320 $this->accessToken = \WP_CLI\Utils\get_flag_value($assoc_args, 'access_token');
321 if (empty($this->accessToken)) {
322 $this->accessToken = \cli\prompt('Enter your HelpScout access token');
323 }
324
325 $mailboxId = \WP_CLI\Utils\get_flag_value($assoc_args, 'mailbox_id');
326 if (empty($mailboxId)) {
327 $mailboxId = \cli\prompt('Enter your HelpScout mailbox ID');
328 }
329
330 if (empty($this->accessToken) || empty($mailboxId)) {
331 \WP_CLI::error('Both access token and mailbox ID are required to proceed.');
332 return;
333 }
334
335 $startPage = $this->checkPreviousMigration('_fs_helpscout_migration_info', $mailboxId);
336
337 $query = [
338 'access_token' => $this->accessToken,
339 'mailbox' => $mailboxId,
340 ];
341
342 $this->processMigration($startPage, 'helpscout', $query);
343
344 } finally {
345 $this->accessToken = null;
346 }
347 }
348 }
349