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 '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; $success = "Downloaded {$downloadResults['successful']} of {$downloadResults['total']} assets"; } 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 { $error = "Failed to update status: " . ($statusResult['response']['error'] ?? 'Unknown error'); } } 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 'load_campaigns_a5': $results['a5_campaigns'] = loadCampaignsByStatus($testRunner, 'A5'); $success = "Loaded " . count($results['a5_campaigns']) . " campaigns with status A5"; $currentTab = 'rework'; break; } } catch (Exception $e) { $error = "Action failed: " . $e->getMessage(); } } // Helper Functions function loadCampaignsByStatus($testRunner, $status) { $statusManager = createStatusManager($testRunner); $response = $statusManager->searchCampaignsByStatus($status); if ($response['success']) { $data = json_decode($response['body'], true); return CampaignFormatter::getActionableCampaigns($response['body'], ['status' => $status]); } 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); } $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

Found Campaigns

Campaign ID:

Asset ID:

Brand:

Market:

A1 - 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.

✅ 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, upload processed assets, and update status to A3

â„šī¸ Coming Soon: Upload functionality will be implemented in next phase

🔄 Rework Workflow: A5 → A6

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

â„šī¸ Coming Soon: Rework workflow will be implemented in next phase