| 1 |
<?php |
| 2 |
|
| 3 |
namespace Templately\Modules\FullSiteImport\Concerns; |
| 4 |
|
| 5 |
use Elementor\Plugin; |
| 6 |
use Error; |
| 7 |
use Exception; |
| 8 |
use Templately\Modules\FullSiteImport\Exception\FatalErrorException; |
| 9 |
use Templately\Modules\FullSiteImport\Exception\RetryableErrorException; |
| 10 |
use Templately\Modules\FullSiteImport\Exception\UnknownErrorException; |
| 11 |
use Templately\Modules\FullSiteImport\Runners\Finalizer; |
| 12 |
use Templately\Modules\FullSiteImport\Utils\LogHandler; |
| 13 |
use Templately\Modules\FullSiteImport\Utils\Utils; |
| 14 |
use Templately\Modules\FullSiteImport\Utils\SessionData; |
| 15 |
use Templately\Modules\FullSiteImport\Utils\AIUtils; |
| 16 |
use Templately\Utils\Helper; |
| 17 |
use Templately\Utils\Options; |
| 18 |
|
| 19 |
/** |
| 20 |
* ReportsStatus — extracted verbatim from FullSiteImport (behavior-preserving). |
| 21 |
* Composed back into FullSiteImport via `use`; $this and method resolution unchanged. |
| 22 |
*/ |
| 23 |
trait ReportsStatus { |
| 24 |
public function handle_import_status($status, $description = '') { |
| 25 |
if ($this->is_import_status_handled === $status) { |
| 26 |
Helper::log("Import status already handled: $status"); |
| 27 |
return null; |
| 28 |
} |
| 29 |
$this->is_import_status_handled = $status; |
| 30 |
|
| 31 |
$download_key = $this->download_key; |
| 32 |
|
| 33 |
$headers = [ |
| 34 |
'Content-Type' => 'application/json', |
| 35 |
'Authorization' => 'Bearer ' . $this->api_key, |
| 36 |
'download_key' => $download_key, |
| 37 |
'download-key' => $download_key, |
| 38 |
'x-templately-ip' => Helper::get_ip(), |
| 39 |
'x-templately-url' => home_url('/'), |
| 40 |
]; |
| 41 |
|
| 42 |
|
| 43 |
$request_params = $this->get_session_data(); |
| 44 |
if(isset($request_params['process_id']) && !empty($request_params['ai_page_ids'])){ |
| 45 |
$updated_ids = AIUtils::get_processed_pages_data($request_params['process_id']); |
| 46 |
$updated_pages = $updated_ids['pages'] ?? []; |
| 47 |
$ai_page_ids = array_reduce($request_params['ai_page_ids'], 'array_merge', array()); |
| 48 |
|
| 49 |
$headers['x-templately-ai-process-id'] = $request_params['process_id']; |
| 50 |
$headers['x-templately-ai-requested-pages'] = implode(',', $ai_page_ids); |
| 51 |
$headers['x-templately-ai-updated-pages'] = implode(',', array_keys($updated_pages)); |
| 52 |
$headers['x-templately-ai-missing-pages'] = implode(',', array_diff($ai_page_ids, array_keys($updated_pages))); |
| 53 |
$headers['x-templately-ai-credit-cost'] = $updated_ids['credit_cost'] ?? null; |
| 54 |
|
| 55 |
// Chat handoff (spec 042 FR-026): the backend keys a generated site by the |
| 56 |
// conversation uuid — no download_key is minted for AI bundles. Forward it |
| 57 |
// so the success/failed endpoints can flip the conversation status |
| 58 |
// (delivered / error) and persist the failure. The uuid was stored on the |
| 59 |
// process data when the import was staged (chatbot-import-prepare). |
| 60 |
$ai_process_data = AIUtils::get_ai_process_data_by_process_id($request_params['process_id']); |
| 61 |
if (!empty($ai_process_data['chat_id'])) { |
| 62 |
$headers['x-templately-ai-chat-uuid'] = $ai_process_data['chat_id']; |
| 63 |
} |
| 64 |
} |
| 65 |
|
| 66 |
|
| 67 |
$extra_headers = $headers; |
| 68 |
|
| 69 |
// Seconds the user spent idling in the customizer step, accumulated by |
| 70 |
// the React import wizard. Sent so the backend can exclude it from the |
| 71 |
// import-time metric (a customizer left open for hours would otherwise |
| 72 |
// inflate the count). Absent for older clients, which the backend |
| 73 |
// treats as zero idle. |
| 74 |
$customizer_idle = isset($request_params['customizer_idle']) ? (int) $request_params['customizer_idle'] : 0; |
| 75 |
|
| 76 |
$normalized = null; |
| 77 |
|
| 78 |
if ($status === 'success') { |
| 79 |
$body = ['type' => 'pack', 'customizer_idle' => $customizer_idle]; |
| 80 |
$normalized = Helper::api_post('v1/import/success', $body, $extra_headers); |
| 81 |
} elseif ($status === 'failed') { |
| 82 |
$body = ['type' => 'pack', 'description' => $description ?: "Something Went wrong.....", 'customizer_idle' => $customizer_idle]; |
| 83 |
$normalized = Helper::api_post('v1/import/failed', $body, $extra_headers); |
| 84 |
} |
| 85 |
|
| 86 |
if (null === $normalized) { |
| 87 |
return null; |
| 88 |
} |
| 89 |
|
| 90 |
// 043 — reporting import status is best-effort telemetry: a failure here must |
| 91 |
// never derail an import that already finished. It is logged with a real code |
| 92 |
// (previously only transport errors were logged at all — a 500 from the cloud |
| 93 |
// was silently treated as success and its body decoded as a result). |
| 94 |
if ($normalized->is_error()) { |
| 95 |
$error = $normalized->error(); |
| 96 |
Helper::log("Import status report failed: {$error->code()} — {$error->message()}", 'ReportsStatus', 'warning'); |
| 97 |
|
| 98 |
return null; |
| 99 |
} |
| 100 |
|
| 101 |
SessionData::set($this->session_id, 'is_import_status_handled', $this->is_import_status_handled); |
| 102 |
|
| 103 |
return $normalized->payload(); |
| 104 |
} |
| 105 |
|
| 106 |
} |
| 107 |
|