validate(); if (!empty($errors)) { die("Configuration Error: " . implode(', ', $errors)); } $config = [ 'baseUrl' => $configV3->getBaseUrl(), 'timeout' => $configV3->get('api.timeout'), 'headers' => [ 'Content-Type' => 'application/json', 'Accept' => 'application/json' ] ]; $collectionPath = __DIR__ . '/' . $configV3->get('postman_collection'); $testRunner = null; $error = null; $success = null; $currentTab = $_GET['tab'] ?? $_POST['tab'] ?? 'download'; try { if (file_exists($collectionPath)) { $testRunner = new TestRunner($collectionPath, $config); } else { $error = "Postman collection file not found: " . $collectionPath; } } catch (Exception $e) { $error = "Error initializing: " . $e->getMessage(); } // Initialize results storage if (!isset($_SESSION['workflow_results'])) { $_SESSION['workflow_results'] = []; } $results = &$_SESSION['workflow_results']; // Handle POST actions if ($_POST && $testRunner) { $action = $_POST['action'] ?? ''; 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"; break; case 'select_campaign_a1': $campaignId = $_POST['campaign_id'] ?? ''; if ($campaignId && isset($results['a1_campaigns'])) { foreach ($results['a1_campaigns'] as $campaign) { if ($campaign['asset_id'] === $campaignId) { $results['selected_campaign'] = $campaign; $success = "Campaign selected: " . $campaign['campaign_name']; break; } } } break; case 'get_master_assets': if (isset($results['selected_campaign'])) { $campaignId = $results['selected_campaign']['asset_id']; $masterFolderId = findMasterAssetsFolder($testRunner, $campaignId, $configV3); if ($masterFolderId) { $results['master_folder_id'] = $masterFolderId; $results['master_assets'] = getAssetsFromFolder($testRunner, $masterFolderId); $success = "Found Master Assets folder with " . count($results['master_assets']) . " assets"; } else { $error = "Master Assets folder not found in campaign"; } } break; case 'download_asset': $assetId = $_POST['asset_id'] ?? ''; $filename = $_POST['filename'] ?? ''; if ($assetId && isset($results['selected_campaign'])) { // Find the asset in our master_assets array to get its full data $assetData = null; if (isset($results['master_assets'])) { foreach ($results['master_assets'] as $asset) { if ($asset['asset_id'] === $assetId) { $assetData = $asset; break; } } } $result = downloadAsset($testRunner, $assetId, $filename, $results['selected_campaign']['campaign_id'], $assetData); $results['last_download'] = $result; if ($result['success']) { $success = "Downloaded: " . $result['filename']; } else { $error = "Download failed: " . $result['error']; } } break; case 'download_all_assets': 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); $statusResult = $statusManager->updateCampaignStatus( $results['selected_campaign']['asset_id'], 'A2' ); if ($statusResult['success']) { $results['status_update'] = $statusResult; $results['selected_campaign']['status'] = 'A2'; $success = "Campaign status updated to A2: Selected Master Assets sent to Agency"; } else { // 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; case 'load_campaigns_a2': $results['a2_campaigns'] = loadCampaignsByStatus($testRunner, 'A2'); $success = "Loaded " . count($results['a2_campaigns']) . " campaigns with status A2"; $currentTab = 'upload'; break; case 'select_campaign_a2': $campaignId = $_POST['campaign_id'] ?? ''; if ($campaignId && isset($results['a2_campaigns'])) { foreach ($results['a2_campaigns'] as $campaign) { if ($campaign['asset_id'] === $campaignId) { $results['selected_campaign_a2'] = $campaign; $success = "Campaign selected: " . $campaign['campaign_name']; $currentTab = 'upload'; break; } } } break; case 'get_upload_folder': if (isset($results['selected_campaign_a2'])) { $campaignId = $results['selected_campaign_a2']['asset_id']; // Find Final Assets or Localized Assets folder for upload $uploadFolderId = findUploadFolder($testRunner, $campaignId, $configV3); if ($uploadFolderId) { $results['upload_folder_id'] = $uploadFolderId; // Get Master Assets to copy their metadata try { $masterFolderId = findMasterAssetsFolder($testRunner, $campaignId, $configV3); if ($masterFolderId) { $fullMasterAssets = getAssetsFromFolder($testRunner, $masterFolderId); // Store lightweight version - only IDs and basic info $results['master_assets_for_upload'] = []; if (!empty($fullMasterAssets)) { foreach ($fullMasterAssets as $asset) { // Only store minimal fields - no huge metadata structure $lightAsset = [ 'asset_id' => $asset['asset_id'] ?? null, 'name' => $asset['name'] ?? 'Unknown', 'mime_type' => $asset['mime_type'] ?? null ]; // Safely extract metadata_model_id if it exists if (isset($asset['metadata_model_id'])) { $lightAsset['metadata_model_id'] = $asset['metadata_model_id']; } // Safely extract security policy IDs only if (isset($asset['security_policy_list']) && is_array($asset['security_policy_list'])) { $policyIds = []; foreach ($asset['security_policy_list'] as $policy) { if (isset($policy['id'])) { $policyIds[] = ['id' => $policy['id']]; } } if (!empty($policyIds)) { $lightAsset['security_policy_list'] = $policyIds; } } $results['master_assets_for_upload'][] = $lightAsset; } } $success = "Found upload folder and " . count($results['master_assets_for_upload']) . " master assets for reference"; } else { $success = "Found upload target folder (no master assets folder found)"; } } catch (Exception $e) { $success = "Found upload target folder (master assets error: " . $e->getMessage() . ")"; } } else { $error = "Upload folder not found in campaign"; } } $currentTab = 'upload'; break; case 'upload_files': if (isset($_FILES['upload_files']) && isset($results['upload_folder_id'])) { // Get selected master asset lightweight data $selectedMasterAssetLight = null; $masterMetadataIndex = $_POST['master_metadata_index'] ?? '0'; // Use master_assets_for_upload (lightweight version) if ($masterMetadataIndex !== '' && isset($results['master_assets_for_upload'][$masterMetadataIndex])) { $selectedMasterAssetLight = $results['master_assets_for_upload'][$masterMetadataIndex]; } elseif (isset($results['master_assets_for_upload']) && !empty($results['master_assets_for_upload'])) { // If no selection, use first master asset as default $selectedMasterAssetLight = $results['master_assets_for_upload'][0]; } // Use the lightweight master asset data directly // Full metadata fetch causes crashes - we only need model ID and security policies $selectedMasterAsset = $selectedMasterAssetLight; // Store debug info about selected master asset and uploaded file $uploadFileName = is_array($_FILES['upload_files']['name']) ? $_FILES['upload_files']['name'][0] : $_FILES['upload_files']['name']; $uploadTmpName = is_array($_FILES['upload_files']['tmp_name']) ? $_FILES['upload_files']['tmp_name'][0] : $_FILES['upload_files']['tmp_name']; $uploadMimeType = file_exists($uploadTmpName) ? mime_content_type($uploadTmpName) : 'Unknown'; $results['upload_debug'] = [ 'selected_master_asset_id' => $selectedMasterAsset['asset_id'] ?? 'N/A', 'selected_master_name' => $selectedMasterAsset['name'] ?? 'N/A', 'metadata_model_id' => $selectedMasterAsset['metadata_model_id'] ?? 'NOT FOUND', 'has_security_policies' => isset($selectedMasterAsset['security_policy_list']) ? 'YES' : 'NO', 'security_policy_count' => isset($selectedMasterAsset['security_policy_list']) ? count($selectedMasterAsset['security_policy_list']) : 0, 'master_mime_type' => $selectedMasterAsset['mime_type'] ?? 'Unknown', 'upload_filename' => $uploadFileName, 'upload_detected_mime' => $uploadMimeType, 'upload_folder_id' => $results['upload_folder_id'] ]; $uploadResults = uploadFiles($testRunner, $_FILES['upload_files'], $results['upload_folder_id'], $selectedMasterAsset); $results['upload_results'] = $uploadResults; if ($uploadResults['successful'] > 0) { $success = "Uploaded {$uploadResults['successful']} of {$uploadResults['total']} files"; } else { $error = "All uploads failed"; } } $currentTab = 'upload'; break; case 'update_status_to_a3': if (isset($results['selected_campaign_a2'])) { $statusManager = createStatusManager($testRunner); $statusResult = $statusManager->updateCampaignStatus( $results['selected_campaign_a2']['asset_id'], 'A3' ); if ($statusResult['success']) { $results['status_update_a3'] = $statusResult; $success = "Campaign status updated to A3: Localized Asset received from Agency"; } else { // 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'; break; case 'debug_all_campaigns_rework': // Check OAuth status first $oauth2Status = $testRunner->getOAuth2Status(); $results['oauth_debug_rework'] = [ '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_rework'] = $campaigns; $results['debug_raw_rework'] = $data; $results['debug_search_response_rework'] = [ '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_rework'] = [ 'http_code' => $response['http_code'], 'url' => $response['url'] ?? 'N/A', 'error' => $response['error'] ?? 'Unknown', 'response_preview' => substr($response['body'] ?? '', 0, 500) ]; } $currentTab = 'rework'; break; case 'reset_to_a5': $campaignId = $_POST['campaign_id'] ?? ''; if ($campaignId) { $statusManager = createStatusManager($testRunner); $statusResult = $statusManager->updateCampaignStatus($campaignId, 'A5'); if ($statusResult['success']) { $success = "Campaign reset to A5 status for testing"; // Clear session data unset($results['selected_campaign_a5']); unset($results['rework_assets']); } 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 A5 (HTTP {$statusResult['http_code']}): {$errorMsg}"; } } $currentTab = 'rework'; break; case 'load_campaigns_a5': $results['a5_campaigns'] = loadCampaignsByStatus($testRunner, 'A5'); $success = "Loaded " . count($results['a5_campaigns']) . " campaigns with status A5"; $currentTab = 'rework'; break; case 'select_campaign_a5': $campaignId = $_POST['campaign_id'] ?? ''; if ($campaignId && isset($results['a5_campaigns'])) { foreach ($results['a5_campaigns'] as $campaign) { if ($campaign['asset_id'] === $campaignId) { $results['selected_campaign_a5'] = $campaign; $success = "Campaign selected: " . $campaign['campaign_name']; $currentTab = 'rework'; break; } } } break; case 'get_rework_assets': if (isset($results['selected_campaign_a5'])) { $campaignId = $results['selected_campaign_a5']['asset_id']; // Find folder with rework assets (could be Final Assets or Rework folder) $reworkFolderId = findUploadFolder($testRunner, $campaignId, $configV3); if ($reworkFolderId) { $results['rework_folder_id'] = $reworkFolderId; $results['rework_assets'] = getAssetsFromFolder($testRunner, $reworkFolderId); $success = "Found " . count($results['rework_assets']) . " assets needing rework"; } else { $error = "Rework assets folder not found"; } } $currentTab = 'rework'; break; case 'download_rework_asset': $assetId = $_POST['asset_id'] ?? ''; $filename = $_POST['filename'] ?? ''; if ($assetId && isset($results['selected_campaign_a5'])) { $assetData = null; if (isset($results['rework_assets'])) { foreach ($results['rework_assets'] as $asset) { if ($asset['asset_id'] === $assetId) { $assetData = $asset; break; } } } $result = downloadAsset($testRunner, $assetId, $filename, $results['selected_campaign_a5']['campaign_id'], $assetData); $results['last_rework_download'] = $result; if ($result['success']) { $success = "Downloaded rework asset: " . $result['filename']; } else { $error = "Download failed: " . $result['error']; } } $currentTab = 'rework'; break; case 'download_all_rework': if (isset($results['rework_assets']) && isset($results['selected_campaign_a5'])) { $downloadResults = downloadAllAssets($testRunner, $results['rework_assets'], $results['selected_campaign_a5']['campaign_id']); $results['rework_bulk_download'] = $downloadResults; $success = "Downloaded {$downloadResults['successful']} of {$downloadResults['total']} rework assets"; } $currentTab = 'rework'; break; case 'update_status_to_a6': if (isset($results['selected_campaign_a5'])) { $statusManager = createStatusManager($testRunner); $statusResult = $statusManager->updateCampaignStatus( $results['selected_campaign_a5']['asset_id'], 'A6' ); if ($statusResult['success']) { $results['status_update_a6'] = $statusResult; $success = "Campaign status updated to A6: Assets to be reworked received by the Agency"; } else { // 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'; break; } } catch (Exception $e) { $error = "Action failed: " . $e->getMessage(); } } // Helper Functions 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->searchAllCampaigns($testRunner); if ($response['success']) { // 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 []; } function findMasterAssetsFolder($testRunner, $campaignId, $configV3) { $masterFolderName = $configV3->getFolderName('master_assets'); $requests = $testRunner->getAvailableRequests(); foreach ($requests as $index => $request) { $name = strtolower($request['name']); if (strpos($name, 'retrieve master asset folder') !== false || strpos($name, 'master asset folder and final') !== false) { $modifiedRequest = $request; $url = is_array($request['request']['url']) ? $request['request']['url']['raw'] : $request['request']['url']; $url = preg_replace('/folders\/[a-f0-9]+\//', "folders/{$campaignId}/", $url); $url = str_replace('{{baseUrl}}', $configV3->getBaseUrl(), $url); if (is_array($modifiedRequest['request']['url'])) { $modifiedRequest['request']['url']['raw'] = $url; } else { $modifiedRequest['request']['url'] = $url; } $result = $testRunner->runSingleTest($modifiedRequest, $index); if ($result['status'] === 'PASS') { $data = json_decode($result['response']['body'], true); $folders = $data['folder_children']['asset_list'] ?? []; foreach ($folders as $folder) { $folderName = extractFolderName($folder); if (strpos($folderName, 'Master') !== false || $folderName === $masterFolderName) { return $folder['asset_id']; } } } break; } } return null; } function extractFolderName($folder) { $nameFields = [ 'INER_NAME_GENERIC', 'ARTESIA.FIELD.NAME', 'FERRERO.FIELD.CAMPAIGN_NAME', 'ARTESIA.FIELD.TITLE' ]; if (isset($folder['metadata']['metadata_element_list'])) { foreach ($folder['metadata']['metadata_element_list'] as $category) { if (isset($category['metadata_element_list'])) { foreach ($category['metadata_element_list'] as $field) { if (in_array($field['id'], $nameFields) && isset($field['value']['value']['value'])) { return $field['value']['value']['value']; } } } } } return $folder['name'] ?? $folder['title'] ?? 'Unnamed'; } function getAssetsFromFolder($testRunner, $folderId) { $requests = $testRunner->getAvailableRequests(); foreach ($requests as $index => $request) { $name = strtolower($request['name']); if (strpos($name, 'retrieve all assets from') !== false) { $modifiedRequest = $request; $url = is_array($request['request']['url']) ? $request['request']['url']['raw'] : $request['request']['url']; $url = preg_replace('/folders\/[a-f0-9]+\//', "folders/{$folderId}/", $url); if (is_array($modifiedRequest['request']['url'])) { $modifiedRequest['request']['url']['raw'] = $url; } else { $modifiedRequest['request']['url'] = $url; } $result = $testRunner->runSingleTest($modifiedRequest, $index); if ($result['status'] === 'PASS') { $data = json_decode($result['response']['body'], true); $assets = $data['folder_children']['asset_list'] ?? []; // Filter out folders, only return files return array_filter($assets, function($asset) { return ($asset['data_type'] ?? '') !== 'CONTAINER'; }); } break; } } return []; } function downloadAsset($testRunner, $assetId, $filename, $campaignId, $assetData = null) { $apiClient = new ApiClient(); $configV3 = new ConfigV3(); $apiClient->setBaseUrl($configV3->getBaseUrl()); // Get OAuth2 token $oauth2Handler = new ReflectionProperty($testRunner, 'oauth2Handler'); $oauth2Handler->setAccessible(true); $oauth2HandlerInstance = $oauth2Handler->getValue($testRunner); if ($oauth2HandlerInstance) { $apiClient->setHeader('Authorization', $oauth2HandlerInstance->getAuthHeader()); } $renditionUrl = null; $debugInfo = []; // If we have asset data from folder listing, use it directly if ($assetData) { $debugInfo['using_cached_asset_data'] = true; // Look for rendition URL in asset_content_info from folder listing if (isset($assetData['asset_content_info']['master_content']['url'])) { $renditionUrl = $assetData['asset_content_info']['master_content']['url']; $debugInfo['found_master_content_url'] = true; } elseif (isset($assetData['asset_content_info'][0]['url'])) { $renditionUrl = $assetData['asset_content_info'][0]['url']; $debugInfo['found_array_url'] = true; } elseif (isset($assetData['asset_content_info']['url'])) { $renditionUrl = $assetData['asset_content_info']['url']; $debugInfo['found_direct_url'] = true; } $debugInfo['has_asset_content_info'] = isset($assetData['asset_content_info']); $debugInfo['asset_content_info_type'] = isset($assetData['asset_content_info']) ? gettype($assetData['asset_content_info']) : 'not set'; } // Fallback: Fetch asset metadata if not provided or rendition not found if (!$renditionUrl) { $debugInfo['fetching_from_api'] = true; $metadataRequest = [ 'method' => 'GET', 'url' => "/v6/assets/{$assetId}?load_type=full" ]; $metadataResponse = $apiClient->executeRequest($metadataRequest); if ($metadataResponse['success']) { $fetchedData = json_decode($metadataResponse['body'], true); $asset = $fetchedData['asset'] ?? $fetchedData; if (isset($asset['asset_content_info']['master_content']['url'])) { $renditionUrl = $asset['asset_content_info']['master_content']['url']; } elseif (isset($asset['asset_content_info'][0]['url'])) { $renditionUrl = $asset['asset_content_info'][0]['url']; } elseif (isset($asset['asset_content_info']['url'])) { $renditionUrl = $asset['asset_content_info']['url']; } $debugInfo['api_has_asset_content_info'] = isset($asset['asset_content_info']); } } // Try direct download if no rendition URL found if (!$renditionUrl) { $renditionUrl = "/v6/assets/{$assetId}/contents"; } // Clean up the URL - remove /otmmapi prefix if present (base URL already has it) $renditionUrl = str_replace('/otmmapi/', '/', $renditionUrl); $debugInfo['final_url'] = $renditionUrl; // Try to download - first attempt with original/master rendition $request = [ 'method' => 'GET', 'url' => $renditionUrl ]; $response = $apiClient->executeRequest($request); $attempts = [['url' => $renditionUrl, 'type' => 'original', 'http_code' => $response['http_code']]]; // If original fails and we have asset data, try preview/thumbnail renditions if ($response['success'] && !empty($response['body'])) { $jsonCheck = json_decode($response['body'], true); if ($jsonCheck && isset($jsonCheck['exception_body'])) { // Original failed, try alternative renditions from asset data $alternativeRenditions = []; if ($assetData && isset($assetData['asset_content_info'])) { $debugInfo['asset_content_info_count'] = count($assetData['asset_content_info']); foreach ($assetData['asset_content_info'] as $key => $contentInfo) { if (is_array($contentInfo)) { $rendType = $contentInfo['rendition_type'] ?? $key; $debugInfo['content_info_keys'][] = $key; if (isset($contentInfo['url'])) { // Add ALL renditions, not just preview/thumbnail $alternativeRenditions[] = [ 'url' => str_replace('/otmmapi/', '/', $contentInfo['url']), 'type' => $rendType ]; } } } $debugInfo['alternative_renditions_found'] = count($alternativeRenditions); } // Try alternative renditions foreach ($alternativeRenditions as $altRendition) { $altRequest = ['method' => 'GET', 'url' => $altRendition['url']]; $altResponse = $apiClient->executeRequest($altRequest); $attempts[] = ['url' => $altRendition['url'], 'type' => $altRendition['type'], 'http_code' => $altResponse['http_code']]; if ($altResponse['success'] && !empty($altResponse['body'])) { $altCheck = json_decode($altResponse['body'], true); if (!$altCheck || !isset($altCheck['exception_body'])) { // Success with alternative rendition! $response = $altResponse; $renditionUrl = $altRendition['url']; $debugInfo['used_rendition'] = $altRendition['type']; break; } } } // Still failed after all attempts $finalCheck = json_decode($response['body'], true); if ($finalCheck && isset($finalCheck['exception_body'])) { return [ 'success' => false, 'error' => $finalCheck['exception_body']['message'] ?? 'File not found in storage', 'http_code' => $finalCheck['exception_body']['http_response_code'] ?? 500, 'debug_message' => $finalCheck['exception_body']['debug_message'] ?? '', 'tried_url' => $renditionUrl, 'debug_info' => $debugInfo, 'all_attempts' => $attempts ]; } } $downloadPath = $configV3->getDownloadPath($campaignId); if (!is_dir($downloadPath)) { mkdir($downloadPath, 0755, true); } $safeFilename = preg_replace('/[^a-zA-Z0-9._-]/', '_', $filename ?: "asset_{$assetId}"); $fullPath = $downloadPath . '/' . $safeFilename; $bytesWritten = file_put_contents($fullPath, $response['body']); return [ 'success' => $bytesWritten !== false, 'filename' => $safeFilename, 'filepath' => $fullPath, 'size' => $bytesWritten, 'asset_id' => $assetId, 'download_method' => 'rendition', 'rendition_url' => $renditionUrl ]; } return [ 'success' => false, 'error' => $response['error'] ?? 'Download failed', 'http_code' => $response['http_code'], 'tried_url' => $renditionUrl ]; } function downloadAllAssets($testRunner, $assets, $campaignId) { $results = [ 'total' => count($assets), 'successful' => 0, 'failed' => 0, 'details' => [] ]; foreach ($assets as $asset) { $filename = extractFolderName($asset); $result = downloadAsset($testRunner, $asset['asset_id'], $filename, $campaignId); if ($result['success']) { $results['successful']++; } else { $results['failed']++; } $results['details'][] = $result; } return $results; } function createStatusManager($testRunner) { $apiClient = new ApiClient(); $configV3 = new ConfigV3(); $apiClient->setBaseUrl($configV3->getBaseUrl()); $oauth2Handler = new ReflectionProperty($testRunner, 'oauth2Handler'); $oauth2Handler->setAccessible(true); $oauth2HandlerInstance = $oauth2Handler->getValue($testRunner); if ($oauth2HandlerInstance) { $apiClient->setHeader('Authorization', $oauth2HandlerInstance->getAuthHeader()); } return new StatusManager($apiClient); } function findUploadFolder($testRunner, $campaignId, $configV3) { $finalFolderName = $configV3->getFolderName('final_assets'); $requests = $testRunner->getAvailableRequests(); foreach ($requests as $index => $request) { $name = strtolower($request['name']); if (strpos($name, 'retrieve master asset folder') !== false || strpos($name, 'master asset folder and final') !== false) { $modifiedRequest = $request; $url = is_array($request['request']['url']) ? $request['request']['url']['raw'] : $request['request']['url']; $url = preg_replace('/folders\/[a-f0-9]+\//', "folders/{$campaignId}/", $url); $url = str_replace('{{baseUrl}}', $configV3->getBaseUrl(), $url); if (is_array($modifiedRequest['request']['url'])) { $modifiedRequest['request']['url']['raw'] = $url; } else { $modifiedRequest['request']['url'] = $url; } $result = $testRunner->runSingleTest($modifiedRequest, $index); if ($result['status'] === 'PASS') { $data = json_decode($result['response']['body'], true); $folders = $data['folder_children']['asset_list'] ?? []; foreach ($folders as $folder) { $folderName = extractFolderName($folder); // Look for Final Assets or Localized folder if (strpos($folderName, 'Final') !== false || strpos($folderName, 'Localized') !== false || $folderName === $finalFolderName) { return $folder['asset_id']; } } } break; } } return null; } function fetchFullAssetMetadata($testRunner, $assetId) { $apiClient = new ApiClient(); $configV3 = new ConfigV3(); $apiClient->setBaseUrl($configV3->getBaseUrl()); // Get OAuth2 token $oauth2Handler = new ReflectionProperty($testRunner, 'oauth2Handler'); $oauth2Handler->setAccessible(true); $oauth2HandlerInstance = $oauth2Handler->getValue($testRunner); if ($oauth2HandlerInstance) { $apiClient->setHeader('Authorization', $oauth2HandlerInstance->getAuthHeader()); } // Fetch full asset with metadata $request = [ 'method' => 'GET', 'url' => "/v6/assets/{$assetId}?load_type=full" ]; $response = $apiClient->executeRequest($request); if ($response['success']) { $data = json_decode($response['body'], true); return $data['asset'] ?? null; } return null; } function uploadFiles($testRunner, $uploadedFiles, $folderId, $selectedMasterAsset = null) { $apiClient = new ApiClient(); $configV3 = new ConfigV3(); $apiClient->setBaseUrl($configV3->getBaseUrl()); $oauth2Handler = new ReflectionProperty($testRunner, 'oauth2Handler'); $oauth2Handler->setAccessible(true); $oauth2HandlerInstance = $oauth2Handler->getValue($testRunner); if ($oauth2HandlerInstance) { $apiClient->setHeader('Authorization', $oauth2HandlerInstance->getAuthHeader()); } $uploader = new AssetUploader($apiClient, $folderId); $results = [ 'total' => 0, 'successful' => 0, 'failed' => 0, 'details' => [] ]; // Handle multiple file upload if (isset($uploadedFiles['tmp_name'])) { $fileCount = is_array($uploadedFiles['tmp_name']) ? count($uploadedFiles['tmp_name']) : 1; $results['total'] = $fileCount; for ($i = 0; $i < $fileCount; $i++) { $tmpName = is_array($uploadedFiles['tmp_name']) ? $uploadedFiles['tmp_name'][$i] : $uploadedFiles['tmp_name']; $fileName = is_array($uploadedFiles['name']) ? $uploadedFiles['name'][$i] : $uploadedFiles['name']; $fileError = is_array($uploadedFiles['error']) ? $uploadedFiles['error'][$i] : $uploadedFiles['error']; if ($fileError !== UPLOAD_ERR_OK) { $results['details'][] = [ 'success' => false, 'filename' => $fileName, 'error' => 'Upload error code: ' . $fileError ]; $results['failed']++; continue; } // Pass the entire selected master asset (not just metadata) and TestRunner $result = $uploader->uploadFile($tmpName, $folderId, [], $selectedMasterAsset, $testRunner); if ($result['success']) { $results['successful']++; } else { $results['failed']++; } $results['details'][] = $result; } } return $results; } $oauth2Status = $testRunner ? $testRunner->getOAuth2Status() : null; $envInfo = $configV3->getEnvironmentInfo(); ?> Content Scaling Workflow V3

đŸŽ¯ Content Scaling Workflow V3

Status-based workflow management for Ferrero DAM

Environment: ()
Base URL:
❌ Error:
✅ Success:
- Expires:

đŸ“Ĩ Download Workflow: A1 → A2

Load campaigns with status A1, download master assets, and update status to A2

🔍 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

Campaign ID:

Asset ID:

Brand:

Market:

Content Scaling Status: - Ready for Localization

Master Assets ( files)

$asset): ?>

ID:
Type: | Size: bytes

âš ī¸ Update Status to A2

Once all assets are downloaded (or attempted), update the campaign status to A2 (Selected Master Assets sent to Agency)

Note: If files don't exist in storage (test environment), you can still update the status to test the workflow progression.

âš ī¸ Status Update Debug Information:
View detailed error information
HTTP Status Code:
Folder ID:
Target Status:
API Response Body:
Request URL:
✅ Download Successful:
Size: bytes | Path:
Method: | URL: ❌ Download Failed:
HTTP Code:
Tried URL:
Details:
Debug:
View all download attempts ()
$att): ?>
. [] - HTTP
Bulk Download Results: of assets downloaded successfully 0): ?>
files failed (may not exist in storage)

📤 Upload Workflow: A2 → A3

Load campaigns with status A2 (assets sent to agency), upload processed files, and update status to A3

Found Campaigns

Campaign ID:

Asset ID:

Brand:

Market:

Content Scaling Status: - Assets Sent to Agency

Selected Campaign: ()
✅ Upload target folder found

Upload Processed Files

✅ Found master assets from this campaign

📋 Select Master Asset Metadata to Use:

Choose which master asset's metadata structure to use for your upload. Your uploaded file will inherit all metadata (model, security, fields) from the selected master asset. Only the filename will be updated to match your new file.

$masterAsset): ?>
â„šī¸ Note: No master assets found.
Click "Find Upload Folder" above to fetch master assets from this campaign.

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

🔍 Upload Debug Info:
Your File: ()
Target Folder ID:

Using Metadata From:
Master Asset ID:
Metadata Model ID:
Has Security Policies: ( policies)
Master MIME Type:

Sending: asset_representation (model ID + security policies only) + manifest + parent_folder_id + files
Note: Full metadata too large to send - using model ID inheritance instead
Upload Results: of files uploaded successfully
View upload details
$detail): ?>
✅
Asset ID: ❌
Error:
HTTP Code:
View API Response
0): ?>

✅ Update Status to A3

Files have been uploaded. Update the campaign status to A3 (Localized Asset received from Agency)

🔄 Rework Workflow: A5 → A6

Load campaigns with status A5 (rework needed), download assets for rework, and update status to A6

🔍 Debug Results: Found Campaigns

OAuth Status: | Expires:

API Response: HTTP - Service Unavailable
Total results from API:
URL:

Showing ALL campaigns - use reset button to change any to A5 for testing:

$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 above)

Found Campaigns Needing Rework

Campaign ID:

Asset ID:

Brand:

Market:

Content Scaling Status: - Rework Needed

Selected Campaign: ()

Rework Assets ( files)

$asset): ?>

ID:
Type: | Size: bytes

âš ī¸ Update Status to A6

Once rework assets are downloaded, update the campaign status to A6 (Assets to be reworked received by the Agency)

✅ Download Successful:
Size: bytes ❌ Download Failed:
Bulk Download Results: of rework assets downloaded