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/Hooks/CLI/FluentCli.php +142 -11 1.10.0 → 2.4.5 View file →
@@ -29,9 +29,9 @@
29 29 \WP_CLI::line('use --key=LICENSE_KEY to activate the license');
30 30 return;
31 31 }
32 32
33 - $licenseKey = trim(sanitize_text_field($assoc_args['key']));
33 + $licenseKey = trim(sanitize_text_field($assoc_args['key'] ?? ''));
34 34
35 35 if (!class_exists('\FluentSupportPro\App\Services\PluginManager\LicenseManager')) {
36 36 \WP_CLI::line('FluentSupport Pro is required');
37 37 return;
@@ -122,14 +122,20 @@
122 122
123 123 /**
124 124 * Check for previous migration data and determine the starting page.
125 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.
126 128 * @return int Page number to start from
127 129 */
128 - private function checkPreviousMigration()
130 + private function checkPreviousMigration($metaKey = '_fs_freshdesk_migration_info', $identifier = null)
129 131 {
130 - $metadata = Meta::where('object_type', '_fs_freshdesk_migration_info')->first();
132 + if ($identifier === null) {
133 + $identifier = $this->domain;
134 + }
131 135
136 + $metadata = Meta::where('object_type', $metaKey)->first();
137 +
132 138 if (empty($metadata)) {
133 139 return 1;
134 140 }
135 141
@@ -135,9 +141,9 @@
135 141
136 142 $previouslyImported = maybe_unserialize($metadata->value ?? []);
137 143 $previousDomain = $metadata->key ?? '';
138 144
139 - if ($previousDomain === $this->domain &&
145 + if ($previousDomain === $identifier &&
140 146 !empty($previouslyImported['has_more']) &&
141 147 $previouslyImported['has_more'] === true &&
142 148 !empty($previouslyImported['next_page'])) {
143 149
@@ -159,15 +165,24 @@
159 165 return 1;
160 166 }
161 167
162 168 /**
163 - * Process the migration by fetching and importing tickets page by page.
169 + * Import tickets page by page until the provider reports no more.
164 170 *
165 - * @param int $startPage Page number to start from
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.
166 174 */
167 - private function processMigration($startPage = 1)
175 + private function processMigration($startPage = 1, $provider = 'freshdesk', $query = null)
168 176 {
169 177 try {
178 + if ($query === null) {
179 + $query = [
180 + 'access_token' => $this->accessToken,
181 + 'domain' => $this->domain,
182 + ];
183 + }
184 +
170 185 $page = $startPage;
171 186 $migrator = new MigratorService;
172 187 $totalImported = 0;
173 188 $totalSkipped = 0;
@@ -174,12 +189,9 @@
174 189
175 190 while (true) {
176 191 \WP_CLI::line("Processing page: $page");
177 192
178 - $result = $migrator->handleImport($page, 'freshdesk', [
179 - 'access_token' => $this->accessToken,
180 - 'domain' => $this->domain
181 - ]);
193 + $result = $migrator->handleImport($page, $provider, $query);
182 194
183 195 if (empty($result) || !isset($result['completed'])) {
184 196 \WP_CLI::warning("Invalid response received for page $page. Stopping migration.");
185 197 break;
@@ -184,8 +196,21 @@
184 196 \WP_CLI::warning("Invalid response received for page $page. Stopping migration.");
185 197 break;
186 198 }
187 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 +
188 213 $imported = count($result['insert_ids'] ?? []);
189 214 $skipped = intval($result['skips'] ?? 0);
190 215
191 216 $totalImported += $imported;
@@ -211,7 +236,113 @@
211 236 $totalSkipped
212 237 ));
213 238 } catch (\Exception $e) {
214 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;
215 346 }
216 347 }
217 348 }