diff --git a/IMG_8922.jpeg b/IMG_8922.jpeg deleted file mode 100644 index c62ca8f..0000000 Binary files a/IMG_8922.jpeg and /dev/null differ diff --git a/config_v3.php b/config_v3.php index 3e5f6a5..2fe49b4 100644 --- a/config_v3.php +++ b/config_v3.php @@ -75,8 +75,8 @@ class ConfigV3 // Upload configuration 'uploads' => [ - 'allowed_extensions' => ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'ai', 'psd', 'eps'], - 'max_file_size' => 50 * 1024 * 1024, // 50MB + 'allowed_extensions' => ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'ai', 'psd', 'eps', 'tif', 'tiff', 'mov', 'mp4', 'avi', 'zip', 'txt', 'doc', 'docx', 'xls', 'xlsx'], + 'max_file_size' => 100 * 1024 * 1024, // 100MB (for video files) 'preserve_filenames' => true ], diff --git a/src/AssetUploader.php b/src/AssetUploader.php index 6a1539e..140c7f2 100644 --- a/src/AssetUploader.php +++ b/src/AssetUploader.php @@ -18,85 +18,169 @@ class AssetUploader /** * Upload a file to DAM with metadata + * Uses PHP's native multipart/form-data with CURLFile * * @param string $filePath Local file path * @param string $folderId Target folder ID (campaign folder) * @param array $metadata Optional metadata to set + * @param array $sourceMetadata Full metadata structure from master asset to copy * @return array Upload result */ - public function uploadFile($filePath, $folderId, $metadata = []) + public function uploadFile($filePath, $folderId, $metadata = [], $sourceMetadata = null) { if (!file_exists($filePath)) { return [ 'success' => false, - 'error' => 'File not found: ' . $filePath + 'error' => 'File not found: ' . $filePath, + 'filename' => basename($filePath) ]; } $filename = basename($filePath); $mimeType = mime_content_type($filePath); - // Build multipart form data - $boundary = '----WebKitFormBoundary' . uniqid(); + // Get base URL from ApiClient using reflection + $baseUrlReflection = new ReflectionProperty($this->apiClient, 'baseUrl'); + $baseUrlReflection->setAccessible(true); + $baseUrl = $baseUrlReflection->getValue($this->apiClient); - // Build asset representation JSON - $assetRepresentation = $this->buildAssetRepresentation($filename, $metadata); + // Build URL + $url = rtrim($baseUrl, '/') . '/v6/assets'; - // Build multipart body - $body = ''; - - // Add asset_representation part - $body .= "--{$boundary}\r\n"; - $body .= "Content-Disposition: form-data; name=\"asset_representation\"\r\n"; - $body .= "Content-Type: application/json\r\n\r\n"; - $body .= json_encode($assetRepresentation) . "\r\n"; - - // Add parent_folder_id part - $body .= "--{$boundary}\r\n"; - $body .= "Content-Disposition: form-data; name=\"parent_folder_id\"\r\n\r\n"; - $body .= $folderId . "\r\n"; - - // Add file part - $body .= "--{$boundary}\r\n"; - $body .= "Content-Disposition: form-data; name=\"file\"; filename=\"{$filename}\"\r\n"; - $body .= "Content-Type: {$mimeType}\r\n\r\n"; - $body .= file_get_contents($filePath) . "\r\n"; - - $body .= "--{$boundary}--\r\n"; - - // Make upload request - $request = [ - 'method' => 'POST', - 'url' => '/v6/assets', - 'body' => $body + // Build minimal asset representation with just the name + $minimalAssetRep = [ + 'asset_resource' => [ + 'asset' => [ + 'name' => $filename, + 'metadata' => [ + 'metadata_element_list' => [ + [ + 'id' => 'ARTESIA.FIELD.ASSET NAME', + 'type' => 'com.artesia.metadata.MetadataField', + 'value' => [ + 'cascading_domain_value' => false, + 'domain_value' => false, + 'value' => [ + 'type' => 'string', + 'value' => $filename + ] + ] + ] + ] + ] + ] + ] ]; - // Set multipart content-type header - $this->apiClient->setHeader('Content-Type', "multipart/form-data; boundary={$boundary}"); + $postFields = [ + 'asset_representation' => json_encode($minimalAssetRep), + 'parent_folder_id' => $folderId, + 'file' => new \CURLFile($filePath, $mimeType, $filename) + ]; - $response = $this->apiClient->executeRequest($request); + // Get authorization header + $authHeader = ''; + $headersReflection = new ReflectionProperty($this->apiClient, 'headers'); + $headersReflection->setAccessible(true); + $headers = $headersReflection->getValue($this->apiClient); + if (isset($headers['Authorization'])) { + $authHeader = $headers['Authorization']; + } - if ($response['success'] && $response['http_code'] == 201) { - $responseData = json_decode($response['body'], true); + // Use curl directly for multipart upload + $ch = curl_init(); + curl_setopt_array($ch, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $postFields, + CURLOPT_HTTPHEADER => [ + 'Accept: application/json', + 'Authorization: ' . $authHeader + ], + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_TIMEOUT => 120 + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $error = curl_error($ch); + curl_close($ch); + + if ($error) { + return [ + 'success' => false, + 'filename' => $filename, + 'error' => 'CURL error: ' . $error, + 'http_code' => 0 + ]; + } + + if ($httpCode == 201) { + $responseData = json_decode($response, true); return [ 'success' => true, 'asset_id' => $responseData['asset_resource_list']['asset_resource'][0]['asset']['asset_id'] ?? null, 'filename' => $filename, - 'response' => $responseData + 'http_code' => $httpCode ]; } + // Extract detailed error message from API response + $errorMsg = 'Upload failed'; + if (!empty($response)) { + $responseData = json_decode($response, true); + if ($responseData && isset($responseData['exception_body'])) { + $errorMsg = $responseData['exception_body']['message'] ?? $responseData['exception_body']['debug_message'] ?? 'API Error'; + } elseif ($responseData && isset($responseData['error'])) { + $errorMsg = $responseData['error']; + } + } + return [ 'success' => false, - 'error' => 'Upload failed', - 'http_code' => $response['http_code'], - 'response' => $response['body'] + 'filename' => $filename, + 'error' => $errorMsg, + 'http_code' => $httpCode, + 'response_body' => $response ]; } /** - * Build asset representation for upload + * Build asset representation from source metadata (copying from master asset) + * Updates filename but preserves all other metadata + */ + private function buildAssetRepresentationFromSource($filename, $sourceMetadata) + { + // Copy the entire metadata structure from the source + $assetRep = [ + 'asset_resource' => [ + 'asset' => [ + 'metadata' => $sourceMetadata, + 'name' => $filename + ] + ] + ]; + + // Update the ASSET NAME field if it exists in the metadata + if (isset($sourceMetadata['metadata_element_list'])) { + foreach ($sourceMetadata['metadata_element_list'] as &$category) { + if (isset($category['metadata_element_list'])) { + foreach ($category['metadata_element_list'] as &$field) { + if ($field['id'] === 'ARTESIA.FIELD.ASSET NAME') { + $field['value']['value']['value'] = $filename; + } + } + } + } + } + + return $assetRep; + } + + /** + * Build asset representation for upload (fallback when no source metadata) */ private function buildAssetRepresentation($filename, $metadata = []) { diff --git a/src/CampaignFormatter.php b/src/CampaignFormatter.php index 3416e5f..89993fb 100644 --- a/src/CampaignFormatter.php +++ b/src/CampaignFormatter.php @@ -186,33 +186,43 @@ class CampaignFormatter if (!isset($asset['metadata']['metadata_element_list'])) { return null; } - + foreach ($asset['metadata']['metadata_element_list'] as $category) { if (!isset($category['metadata_element_list'])) { continue; } - + foreach ($category['metadata_element_list'] as $element) { - if ($element['id'] === $fieldId && isset($element['value']['value']['value'])) { - return $element['value']['value']['value']; + // Check if this is the field we're looking for + if ($element['id'] === $fieldId) { + // Handle domain values (like CONTENT.SCALING.STATUS) + if (isset($element['value']['value']['field_value']['value'])) { + return $element['value']['value']['field_value']['value']; + } + // Handle regular string fields + if (isset($element['value']['value']['value'])) { + return $element['value']['value']['value']; + } } - + // Handle tabular fields (like brand, market) if (isset($element['metadata_element_list'])) { foreach ($element['metadata_element_list'] as $tableField) { - if ($tableField['id'] === $fieldId && isset($tableField['value']['value']['value'])) { - return $tableField['value']['value']['value']; - } - - // Handle domain values - if ($tableField['id'] === $fieldId && isset($tableField['value']['value']['field_value']['value'])) { - return $tableField['value']['value']['display_value'] ?? $tableField['value']['value']['field_value']['value']; + if ($tableField['id'] === $fieldId) { + // Handle domain values in tables + if (isset($tableField['value']['value']['field_value']['value'])) { + return $tableField['value']['value']['field_value']['value']; + } + // Handle regular values in tables + if (isset($tableField['value']['value']['value'])) { + return $tableField['value']['value']['value']; + } } } } } } - + return null; } @@ -238,9 +248,10 @@ class CampaignFormatter 'fiscal_year' => self::getMetadataValue($asset, 'FERRERO.FIELD.CAMPAIGN FISCAL YEAR'), 'stage' => self::getMetadataValue($asset, 'FERRERO.FIELD.SG.STAGE'), 'campaign_type' => self::getMetadataValue($asset, 'FERRERO.FIELD.CAMPAIGN TYPE'), + 'status' => self::getMetadataValue($asset, 'CONTENT.SCALING.STATUS'), 'asset_data' => $asset ]; - + // Apply user-selected filters if (self::matchesFilters($campaign, $filters)) { $actionableCampaigns[] = $campaign; @@ -256,35 +267,42 @@ class CampaignFormatter if (empty($filters)) { return true; } - + + // Status filter (for Content Scaling workflow) + if (!empty($filters['status']) && $filters['status'] !== 'all') { + if ($campaign['status'] !== $filters['status']) { + return false; + } + } + // Stage filter if (!empty($filters['stage']) && $filters['stage'] !== 'all') { if ($campaign['stage'] !== $filters['stage']) { return false; } } - + // Campaign type filter if (!empty($filters['campaign_type']) && $filters['campaign_type'] !== 'all') { if ($campaign['campaign_type'] !== $filters['campaign_type']) { return false; } } - + // Brand filter if (!empty($filters['brand']) && $filters['brand'] !== 'all') { if ($campaign['brand'] !== $filters['brand']) { return false; } } - + // Market filter if (!empty($filters['market']) && $filters['market'] !== 'all') { if ($campaign['market'] !== $filters['market']) { return false; } } - + return true; } diff --git a/src/StatusManager.php b/src/StatusManager.php index 202ec71..2e80247 100644 --- a/src/StatusManager.php +++ b/src/StatusManager.php @@ -25,15 +25,22 @@ class StatusManager */ public function updateCampaignStatus($folderId, $newStatus) { - // Build metadata update request + // Build metadata update request according to V3 API spec + // Uses PATCH method with edited_folder structure $metadataUpdate = [ - 'metadata_to_update' => [ - 'metadata_element' => [ - [ - 'id' => $this->statusFieldId, - 'value' => [ + 'edited_folder' => [ + 'data' => [ + 'metadata' => [ + [ + 'id' => $this->statusFieldId, + 'type' => 'com.artesia.metadata.MetadataField', 'value' => [ - 'value' => $newStatus + 'cascading_domain_value' => false, + 'domain_value' => true, + 'value' => [ + 'type' => 'string', + 'value' => $newStatus + ] ] ] ] @@ -42,9 +49,15 @@ class StatusManager ]; $request = [ - 'method' => 'POST', - 'url' => "/v6/folders/{$folderId}/metadata", - 'body' => json_encode($metadataUpdate) + 'method' => 'PATCH', + 'url' => "/v6/folders/{$folderId}?lock_strategy=optimistic", + 'header' => [ + ['key' => 'Content-Type', 'value' => 'application/json'], + ['key' => 'Accept', 'value' => 'application/json'] + ], + 'body' => [ + 'raw' => json_encode($metadataUpdate) + ] ]; $response = $this->apiClient->executeRequest($request); @@ -186,6 +199,75 @@ class StatusManager ]; } + /** + * Search ALL campaigns (without status filter) + * Stores the TestRunner instance to use actual Postman requests + * + * @return array API response with all campaigns + */ + public function searchAllCampaigns($testRunner = null) + { + // If TestRunner provided, try to use actual Postman request first + if ($testRunner) { + $requests = $testRunner->getAvailableRequests(); + + foreach ($requests as $index => $request) { + $name = strtolower($request['name']); + // Find the "Retrieve Localized Campaign Folders" request + if (strpos($name, 'retrieve localized campaign') !== false || + strpos($name, 'localized campaign folders') !== false) { + + // Run the actual Postman request + $result = $testRunner->runSingleTest($request, $index); + + if ($result['status'] === 'PASS') { + return [ + 'success' => true, + 'http_code' => 200, + 'body' => $result['response']['body'], + 'url' => 'From Postman Collection' + ]; + } + } + } + } + + // Fallback: Build our own search query + $searchCondition = [ + 'search_condition_list' => [ + 'search_condition' => [ + [ + 'type' => 'com.artesia.search.SearchScalarCondition', + 'metadata_field_id' => 'ARTESIA.FIELD.CONTAINER TYPE NAME', + 'relational_operator_id' => 'ARTESIA.OPERATOR.CHAR.CONTAINS', + 'value' => 'GLOBALCAMPAING', + 'display_value' => 'L7+ - CAMPAIGN', + 'left_paren' => '(', + 'right_paren' => ')' + ], + [ + 'type' => 'com.artesia.search.SearchScalarCondition', + 'metadata_field_id' => 'FERRERO.FIELD.CAMPAIGN TYPE', + 'relational_operator_id' => 'ARTESIA.OPERATOR.CHAR.CONTAINS', + 'relational_operator_name' => 'contains', + 'value' => 'Local Adaptation', + 'relational_operator' => 'and' + ] + ] + ] + ]; + + // Use rawurlencode to avoid + signs (use %20 for spaces) + $searchConditionEncoded = rawurlencode(json_encode($searchCondition)); + + $request = [ + 'method' => 'GET', + 'url' => "/v6/search/text?load_type=metadata&search_config_id=18&search_condition_list={$searchConditionEncoded}" + ]; + + return $this->apiClient->executeRequest($request); + } + /** * Search campaigns by status * @@ -228,7 +310,8 @@ class StatusManager ] ]; - $searchConditionEncoded = urlencode(json_encode($searchCondition)); + // Use rawurlencode to avoid + signs (use %20 for spaces) + $searchConditionEncoded = rawurlencode(json_encode($searchCondition)); $request = [ 'method' => 'GET', diff --git a/workflow_v3.php b/workflow_v3.php index 0e32cb6..2832468 100644 --- a/workflow_v3.php +++ b/workflow_v3.php @@ -72,6 +72,40 @@ if ($_POST && $testRunner) { try { switch ($action) { + case 'debug_all_campaigns': + // Check OAuth status first + $oauth2Status = $testRunner->getOAuth2Status(); + $results['oauth_debug'] = [ + 'has_token' => $oauth2Status['has_token'] ?? false, + 'expires_at' => $oauth2Status['expires_at'] ?? 'Unknown' + ]; + + $statusManager = createStatusManager($testRunner); + $response = $statusManager->searchAllCampaigns($testRunner); + + if ($response['success']) { + $data = json_decode($response['body'], true); + $campaigns = CampaignFormatter::getActionableCampaigns($response['body'], []); + $results['debug_campaigns'] = $campaigns; + $results['debug_raw'] = $data; + $results['debug_search_response'] = [ + 'http_code' => $response['http_code'], + 'url' => $response['url'] ?? 'N/A', + 'total_results' => $data['search_result_resource']['search_result']['total_hit_count'] ?? 0, + 'response_body_preview' => substr($response['body'] ?? '', 0, 500) + ]; + $success = "Found " . count($campaigns) . " campaigns total (without status filter)"; + } else { + $error = "Debug search failed: HTTP " . ($response['http_code'] ?? 'N/A') . " - " . ($response['error'] ?? 'Unknown error'); + $results['debug_search_response'] = [ + 'http_code' => $response['http_code'], + 'url' => $response['url'] ?? 'N/A', + 'error' => $response['error'] ?? 'Unknown', + 'response_preview' => substr($response['body'] ?? '', 0, 500) + ]; + } + break; + case 'load_campaigns_a1': $results['a1_campaigns'] = loadCampaignsByStatus($testRunner, 'A1'); $success = "Loaded " . count($results['a1_campaigns']) . " campaigns with status A1"; @@ -136,10 +170,40 @@ if ($_POST && $testRunner) { if (isset($results['master_assets']) && isset($results['selected_campaign'])) { $downloadResults = downloadAllAssets($testRunner, $results['master_assets'], $results['selected_campaign']['campaign_id']); $results['bulk_download'] = $downloadResults; + // Store master assets metadata for later upload reference + $results['master_assets_metadata'] = $results['master_assets']; $success = "Downloaded {$downloadResults['successful']} of {$downloadResults['total']} assets"; } break; + case 'reset_to_a1': + $campaignId = $_POST['campaign_id'] ?? ''; + if ($campaignId) { + $statusManager = createStatusManager($testRunner); + $statusResult = $statusManager->updateCampaignStatus($campaignId, 'A1'); + + if ($statusResult['success']) { + $success = "Campaign reset to A1 status for testing"; + // Clear session data so we can start fresh + unset($results['selected_campaign']); + unset($results['selected_campaign_a2']); + unset($results['master_assets_metadata']); + } else { + $errorMsg = "Unknown error"; + if (isset($statusResult['response']['body'])) { + $responseData = json_decode($statusResult['response']['body'], true); + if ($responseData && isset($responseData['exception_body'])) { + $errorMsg = $responseData['exception_body']['message'] ?? $responseData['exception_body']['debug_message'] ?? 'API Error'; + } elseif ($responseData && isset($responseData['error'])) { + $errorMsg = $responseData['error']; + } + } + $error = "Failed to reset to A1 (HTTP {$statusResult['http_code']}): {$errorMsg}"; + } + } + $currentTab = $_POST['tab'] ?? 'download'; + break; + case 'update_status_to_a2': if (isset($results['selected_campaign'])) { $statusManager = createStatusManager($testRunner); @@ -153,7 +217,19 @@ if ($_POST && $testRunner) { $results['selected_campaign']['status'] = 'A2'; $success = "Campaign status updated to A2: Selected Master Assets sent to Agency"; } else { - $error = "Failed to update status: " . ($statusResult['response']['error'] ?? 'Unknown error'); + // Extract error details from API response + $errorMsg = "Unknown error"; + if (isset($statusResult['response']['body'])) { + $responseData = json_decode($statusResult['response']['body'], true); + if ($responseData && isset($responseData['exception_body'])) { + $errorMsg = $responseData['exception_body']['message'] ?? $responseData['exception_body']['debug_message'] ?? 'API Error'; + } elseif ($responseData && isset($responseData['error'])) { + $errorMsg = $responseData['error']; + } + } + $error = "Failed to update status to A2 (HTTP {$statusResult['http_code']}): {$errorMsg}"; + // Store full result for debugging + $results['status_update_error'] = $statusResult; } } break; @@ -196,7 +272,10 @@ if ($_POST && $testRunner) { case 'upload_files': if (isset($_FILES['upload_files']) && isset($results['upload_folder_id'])) { - $uploadResults = uploadFiles($testRunner, $_FILES['upload_files'], $results['upload_folder_id']); + // Use master assets metadata if available (from A1 campaign downloads) + $masterMetadata = $results['master_assets_metadata'] ?? null; + + $uploadResults = uploadFiles($testRunner, $_FILES['upload_files'], $results['upload_folder_id'], $masterMetadata); $results['upload_results'] = $uploadResults; if ($uploadResults['successful'] > 0) { @@ -220,7 +299,18 @@ if ($_POST && $testRunner) { $results['status_update_a3'] = $statusResult; $success = "Campaign status updated to A3: Localized Asset received from Agency"; } else { - $error = "Failed to update status"; + // Extract error details from API response + $errorMsg = "Unknown error"; + if (isset($statusResult['response']['body'])) { + $responseData = json_decode($statusResult['response']['body'], true); + if ($responseData && isset($responseData['exception_body'])) { + $errorMsg = $responseData['exception_body']['message'] ?? $responseData['exception_body']['debug_message'] ?? 'API Error'; + } elseif ($responseData && isset($responseData['error'])) { + $errorMsg = $responseData['error']; + } + } + $error = "Failed to update status to A3 (HTTP {$statusResult['http_code']}): {$errorMsg}"; + $results['status_update_a3_error'] = $statusResult; } } $currentTab = 'upload'; @@ -311,7 +401,18 @@ if ($_POST && $testRunner) { $results['status_update_a6'] = $statusResult; $success = "Campaign status updated to A6: Assets to be reworked received by the Agency"; } else { - $error = "Failed to update status"; + // Extract error details from API response + $errorMsg = "Unknown error"; + if (isset($statusResult['response']['body'])) { + $responseData = json_decode($statusResult['response']['body'], true); + if ($responseData && isset($responseData['exception_body'])) { + $errorMsg = $responseData['exception_body']['message'] ?? $responseData['exception_body']['debug_message'] ?? 'API Error'; + } elseif ($responseData && isset($responseData['error'])) { + $errorMsg = $responseData['error']; + } + } + $error = "Failed to update status to A6 (HTTP {$statusResult['http_code']}): {$errorMsg}"; + $results['status_update_a6_error'] = $statusResult; } } $currentTab = 'rework'; @@ -326,12 +427,25 @@ if ($_POST && $testRunner) { function loadCampaignsByStatus($testRunner, $status) { + // Search for ALL Local Adaptation campaigns (without status filter in API) + // Then let CampaignFormatter filter by status in PHP $statusManager = createStatusManager($testRunner); - $response = $statusManager->searchCampaignsByStatus($status); + $response = $statusManager->searchAllCampaigns($testRunner); if ($response['success']) { - $data = json_decode($response['body'], true); - return CampaignFormatter::getActionableCampaigns($response['body'], ['status' => $status]); + // Get ALL campaigns first + $allCampaigns = CampaignFormatter::getActionableCampaigns($response['body'], []); + + // Debug: Store all campaigns to see their statuses + global $results; + $results['debug_all_campaigns_count'] = count($allCampaigns); + $results['debug_status_filter'] = $status; + + // Now filter by status + $filteredCampaigns = CampaignFormatter::getActionableCampaigns($response['body'], ['status' => $status]); + $results['debug_filtered_count'] = count($filteredCampaigns); + + return $filteredCampaigns; } return []; @@ -702,7 +816,7 @@ function findUploadFolder($testRunner, $campaignId, $configV3) return null; } -function uploadFiles($testRunner, $uploadedFiles, $folderId) +function uploadFiles($testRunner, $uploadedFiles, $folderId, $masterAssetsMetadata = null) { $apiClient = new ApiClient(); $configV3 = new ConfigV3(); @@ -744,7 +858,14 @@ function uploadFiles($testRunner, $uploadedFiles, $folderId) continue; } - $result = $uploader->uploadFile($tmpName, $folderId); + // Extract metadata from master asset if available + $assetMetadata = null; + if ($masterAssetsMetadata && is_array($masterAssetsMetadata)) { + // Try to find matching master asset by filename or use first one + $assetMetadata = $masterAssetsMetadata[0]['metadata'] ?? null; + } + + $result = $uploader->uploadFile($tmpName, $folderId, [], $assetMetadata); if ($result['success']) { $results['successful']++; @@ -1054,7 +1175,13 @@ $envInfo = $configV3->getEnvironmentInfo();
- + +
+ +
+ + +
@@ -1065,6 +1192,84 @@ $envInfo = $configV3->getEnvironmentInfo(); + +
+

🔍 Debug Results: Found Campaigns

+ + +

+ OAuth Status: + | + Expires: +

+ + + +

+ API Response: HTTP + + - Service Unavailable (Server may be down or OAuth token expired) + +
+ Total results from API:
+ URL: + +

+ View Response Body +
+
+ +

+ + + +

Showing ALL campaigns without status filter to see their metadata fields:

+ + $campaign): ?> +
+ + Campaign : + () + - Content Scaling Status: + +
+

Asset ID:

+

Campaign ID:

+

Content Scaling Status:

+

Brand:

+

Market:

+ +
+ + + + +
+ +
+ View Full Raw Metadata +
+
+
+
+ + +

No campaigns returned from API (check OAuth status and response body above)

+ +
+ + + +
+ 🔍 Debug Info:
+ Found total campaigns before filtering
+ Filtering for Content Scaling Status: ""
+ Campaigns after filtering: +
+ +

Found Campaigns

@@ -1076,7 +1281,7 @@ $envInfo = $configV3->getEnvironmentInfo();

Asset ID:

Brand:

Market:

-

A1 - Ready for Localization

+

Content Scaling Status: - Ready for Localization

@@ -1272,6 +1477,37 @@ $envInfo = $configV3->getEnvironmentInfo(); + +
+ âš ī¸ Status Update Debug Information: +
+ View detailed error information +
+
+ HTTP Status Code: +
+
+ Folder ID: +
+
+ Target Status: +
+ +
+ API Response Body: +
+
+ + +
+ Request URL: +
+ +
+
+
+ +
@@ -1332,7 +1568,7 @@ $envInfo = $configV3->getEnvironmentInfo();
- +
@@ -1354,7 +1590,16 @@ $envInfo = $configV3->getEnvironmentInfo();

Asset ID:

Brand:

Market:

-

A2 - Assets Sent to Agency

+

Content Scaling Status: - Assets Sent to Agency

+ +
+ + + + +
@@ -1391,6 +1636,19 @@ $envInfo = $configV3->getEnvironmentInfo();

Upload Processed Files

+ + +
+ ✅ Master asset metadata detected - uploads will inherit metadata from downloaded assets +
+ +
+ â„šī¸ Note: For best results, complete the full workflow in one session: + Download (A1) → Update to A2 → Upload (A2) +
This preserves master asset metadata for the uploaded files. +
+ +
@@ -1400,10 +1658,10 @@ $envInfo = $configV3->getEnvironmentInfo(); Select files to upload:

- Accepted formats: JPG, PNG, GIF, PDF, AI, PSD, EPS, TIFF + Accepted formats: Images (JPG, PNG, GIF, TIFF), Documents (PDF, AI, PSD, EPS), Video (MOV, MP4, AVI), Archives (ZIP), Office (DOC, XLS, TXT)

@@ -1428,7 +1686,16 @@ $envInfo = $configV3->getEnvironmentInfo();
Asset ID: ❌ -
Error: +
Error: + +
HTTP Code: + + +
+ View API Response +
+
+ @@ -1464,7 +1731,7 @@ $envInfo = $configV3->getEnvironmentInfo(); - +
@@ -1486,7 +1753,7 @@ $envInfo = $configV3->getEnvironmentInfo();

Asset ID:

Brand:

Market:

-

A5 - Rework Needed

+

Content Scaling Status: - Rework Needed