ferrero-opentext/workflow_v3.php
DJP c4eec014a4 Add test upload feature for direct folder testing
New test upload panel in Upload workflow:
- Upload directly to any folder ID (bypasses campaign selection)
- Pre-filled with test folder: e96080ba0cd1427d253a28a87504b6665eaa02cb
- Folder ID can be edited for testing different folders
- Shows success/failure with full error details
- Uses same upload mechanism as regular workflow

Use case:
- Test if specific folders allow uploads
- Bypass campaign workflow for testing
- Verify folder permissions
- Isolate upload issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-27 13:12:25 -04:00

2350 lines
122 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
session_start();
// Clear session on reset
if (isset($_GET['reset']) || isset($_POST['reset'])) {
session_destroy();
session_start();
header('Location: workflow_v3.php');
exit;
}
// Clear specific workflow results
if (isset($_POST['clear_results'])) {
unset($_SESSION['workflow_results']);
$_SESSION['workflow_results'] = [];
header('Location: workflow_v3.php?tab=' . ($_POST['tab'] ?? 'download'));
exit;
}
require_once 'config_v3.php';
require_once 'src/TestRunner.php';
require_once 'src/CampaignFormatter.php';
require_once 'src/AssetDownloader.php';
require_once 'src/MetadataExtractor.php';
require_once 'src/StatusManager.php';
require_once 'src/ApiClient.php';
require_once 'src/AssetUploader.php';
$configV3 = new ConfigV3();
$errors = $configV3->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_asset_metadata':
$assetId = $_POST['asset_id'] ?? '';
$filename = $_POST['filename'] ?? 'metadata.json';
if ($assetId && isset($results['master_assets'])) {
// Find the asset in master_assets
foreach ($results['master_assets'] as $asset) {
if ($asset['asset_id'] === $assetId) {
// Create JSON file
$jsonFilename = pathinfo($filename, PATHINFO_FILENAME) . '_metadata.json';
$jsonContent = json_encode($asset, JSON_PRETTY_PRINT);
// Send as download
header('Content-Type: application/json');
header('Content-Disposition: attachment; filename="' . $jsonFilename . '"');
header('Content-Length: ' . strlen($jsonContent));
echo $jsonContent;
exit;
}
}
}
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 'test_upload_to_folder':
// Test upload to specific folder provided by Ferrero team
$testFolderId = $_POST['test_folder_id'] ?? 'e96080ba0cd1427d253a28a87504b6665eaa02cb';
if (isset($_FILES['test_upload_file'])) {
$tmpName = $_FILES['test_upload_file']['tmp_name'];
$fileName = $_FILES['test_upload_file']['name'];
$fileError = $_FILES['test_upload_file']['error'];
if ($fileError === UPLOAD_ERR_OK) {
$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, $testFolderId);
$result = $uploader->uploadFile($tmpName, $testFolderId, [], null, $testRunner);
$results['test_upload_result'] = $result;
$results['test_folder_id'] = $testFolderId;
if ($result['success']) {
$success = "✅ TEST UPLOAD SUCCESSFUL to folder {$testFolderId}!";
} else {
$error = "Test upload failed: " . $result['error'];
}
} else {
$error = "File upload error: " . $fileError;
}
}
$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();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content Scaling Workflow V3</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 { margin-bottom: 10px; }
.header p { opacity: 0.9; }
.env-info {
background: rgba(255,255,255,0.2);
padding: 10px;
border-radius: 4px;
margin-top: 15px;
font-size: 13px;
}
.tabs {
display: flex;
background: #f8f9fa;
border-bottom: 2px solid #dee2e6;
}
.tab {
flex: 1;
padding: 15px 20px;
text-align: center;
cursor: pointer;
border: none;
background: transparent;
font-size: 16px;
font-weight: 500;
color: #6c757d;
transition: all 0.3s;
}
.tab:hover { background: #e9ecef; }
.tab.active {
background: white;
color: #667eea;
border-bottom: 3px solid #667eea;
}
.tab-content {
padding: 30px;
display: none;
}
.tab-content.active { display: block; }
.alert {
padding: 12px 20px;
border-radius: 6px;
margin-bottom: 20px;
}
.alert-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s;
margin-right: 10px;
margin-bottom: 10px;
}
.btn-primary {
background: #667eea;
color: white;
}
.btn-primary:hover { background: #5568d3; }
.btn-success {
background: #28a745;
color: white;
}
.btn-success:hover { background: #218838; }
.btn-danger {
background: #dc3545;
color: white;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.campaign-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
margin: 20px 0;
}
.campaign-card {
background: #f8f9fa;
border: 2px solid #dee2e6;
border-radius: 8px;
padding: 20px;
cursor: pointer;
transition: all 0.3s;
}
.campaign-card:hover {
border-color: #667eea;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
}
.campaign-card.selected {
border-color: #28a745;
background: #f8fff9;
}
.campaign-card h3 {
color: #333;
margin-bottom: 10px;
}
.campaign-card p {
margin: 5px 0;
font-size: 14px;
color: #666;
}
.asset-list {
background: #f8f9fa;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
.asset-item {
background: white;
border: 1px solid #dee2e6;
border-radius: 6px;
padding: 15px;
margin: 10px 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.asset-info {
flex: 1;
}
.asset-actions {
display: flex;
gap: 10px;
}
.metadata-display {
background: #e9ecef;
padding: 15px;
border-radius: 6px;
margin-top: 10px;
font-size: 12px;
font-family: monospace;
max-height: 300px;
overflow-y: auto;
display: none;
}
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.status-a1 { background: #fff3cd; color: #856404; }
.status-a2 { background: #cfe2ff; color: #084298; }
.status-a3 { background: #d1e7dd; color: #0f5132; }
.status-a5 { background: #f8d7da; color: #842029; }
.status-a6 { background: #e2d9f3; color: #432874; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎯 Content Scaling Workflow V3</h1>
<p>Status-based workflow management for Ferrero DAM</p>
<div class="env-info">
<strong>Environment:</strong> <?= htmlspecialchars($envInfo['description']) ?>
(<?= htmlspecialchars($envInfo['name']) ?>)
<br>
<strong>Base URL:</strong> <?= htmlspecialchars($envInfo['baseUrl']) ?>
</div>
</div>
<?php if ($error): ?>
<div style="padding: 20px;">
<div class="alert alert-error">
<strong>❌ Error:</strong> <?= htmlspecialchars($error) ?>
</div>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div style="padding: 20px;">
<div class="alert alert-success">
<strong>✅ Success:</strong> <?= htmlspecialchars($success) ?>
</div>
</div>
<?php endif; ?>
<?php if ($oauth2Status && $oauth2Status['enabled']): ?>
<div style="padding: 20px; padding-bottom: 0;">
<div class="alert alert-<?= ($oauth2Status['has_token'] ?? false) ? 'success' : 'error' ?>">
<?= ($oauth2Status['has_token'] ?? false) ? '✅ OAuth2 Token Active' : '❌ OAuth2 Token Issue' ?>
<?php if (($oauth2Status['has_token'] ?? false) && isset($oauth2Status['expires_at'])): ?>
- Expires: <?= htmlspecialchars($oauth2Status['expires_at']) ?>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<div class="tabs">
<button class="tab <?= $currentTab === 'download' ? 'active' : '' ?>"
onclick="switchTab('download')">
📥 Download Workflow (A1→A2)
</button>
<button class="tab <?= $currentTab === 'upload' ? 'active' : '' ?>"
onclick="switchTab('upload')">
📤 Upload Workflow (A2→A3)
</button>
<button class="tab <?= $currentTab === 'rework' ? 'active' : '' ?>"
onclick="switchTab('rework')">
🔄 Rework Workflow (A5→A6)
</button>
</div>
<!-- Download Workflow Tab -->
<div id="tab-download" class="tab-content <?= $currentTab === 'download' ? 'active' : '' ?>">
<h2>📥 Download Workflow: A1 → A2</h2>
<p style="color: #666; margin: 10px 0 20px 0;">
Load campaigns with status A1, download master assets, and update status to A2
</p>
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="load_campaigns_a1">
<button type="submit" class="btn btn-primary">Load Campaigns (Content Scaling Status = A1)</button>
</form>
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="debug_all_campaigns">
<button type="submit" class="btn btn-secondary">🔍 Debug: Load ALL Campaigns (no filter)</button>
</form>
<?php if (!empty($results)): ?>
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="clear_results" value="1">
<button type="submit" class="btn btn-secondary">🗑️ Clear Workflow Data</button>
</form>
<?php endif; ?>
<?php if (isset($results['debug_campaigns']) || isset($results['debug_search_response'])): ?>
<div class="alert alert-<?= ($results['debug_search_response']['http_code'] ?? 0) == 503 ? 'error' : 'info' ?>" style="margin-top: 30px;">
<h3>🔍 Debug Results: Found <?= count($results['debug_campaigns'] ?? []) ?> Campaigns</h3>
<?php if (isset($results['oauth_debug'])): ?>
<p style="font-size: 13px; margin: 10px 0; padding: 10px; background: white; border-radius: 4px;">
<strong>OAuth Status:</strong>
<?= $results['oauth_debug']['has_token'] ? '✅ Token Active' : '❌ No Token' ?> |
Expires: <?= htmlspecialchars($results['oauth_debug']['expires_at']) ?>
</p>
<?php endif; ?>
<?php if (isset($results['debug_search_response'])): ?>
<p style="font-size: 13px; margin: 10px 0; padding: 10px; background: white; border-radius: 4px;">
<strong>API Response:</strong> HTTP <?= $results['debug_search_response']['http_code'] ?>
<?php if ($results['debug_search_response']['http_code'] == 503): ?>
<span style="color: #dc3545; font-weight: bold;">- Service Unavailable (Server may be down or OAuth token expired)</span>
<?php endif; ?>
<br>
<strong>Total results from API:</strong> <?= $results['debug_search_response']['total_results'] ?? 0 ?><br>
<strong>URL:</strong> <code style="font-size: 11px;"><?= htmlspecialchars($results['debug_search_response']['url']) ?></code>
<?php if (isset($results['debug_search_response']['response_body_preview'])): ?>
<details style="margin-top: 10px;">
<summary style="cursor: pointer;">View Response Body</summary>
<pre style="font-size: 11px; background: #f8f9fa; padding: 10px; margin-top: 5px;"><?= htmlspecialchars($results['debug_search_response']['response_body_preview']) ?></pre>
</details>
<?php endif; ?>
</p>
<?php endif; ?>
<?php if (!empty($results['debug_campaigns'])): ?>
<p>Showing ALL campaigns without status filter to see their metadata fields:</p>
<?php foreach ($results['debug_campaigns'] as $idx => $campaign): ?>
<details style="margin: 15px 0; background: white; padding: 15px; border-radius: 6px;">
<summary style="cursor: pointer; font-weight: 600;">
Campaign <?= $idx + 1 ?>: <?= htmlspecialchars($campaign['campaign_name'] ?? 'Unnamed') ?>
(<?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?>)
- Content Scaling Status: <span class="status-badge status-<?= strtolower($campaign['status'] ?? 'unknown') ?>"><?= htmlspecialchars($campaign['status'] ?? 'NOT FOUND') ?></span>
</summary>
<div style="margin-top: 15px;">
<p><strong>Asset ID:</strong> <?= htmlspecialchars($campaign['asset_id']) ?></p>
<p><strong>Campaign ID:</strong> <?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?></p>
<p><strong>Content Scaling Status:</strong> <?= htmlspecialchars($campaign['status'] ?? 'NOT FOUND') ?></p>
<p><strong>Brand:</strong> <?= htmlspecialchars($campaign['brand'] ?? 'N/A') ?></p>
<p><strong>Market:</strong> <?= htmlspecialchars($campaign['market'] ?? 'N/A') ?></p>
<form method="POST" style="margin-top: 15px; display: inline-block;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="reset_to_a1">
<input type="hidden" name="campaign_id" value="<?= htmlspecialchars($campaign['asset_id']) ?>">
<button type="submit" class="btn btn-danger" onclick="return confirm('Reset campaign <?= htmlspecialchars($campaign['campaign_name']) ?> to A1 status?')">
🔄 Reset to A1 (for testing)
</button>
</form>
<details style="margin-top: 10px;">
<summary style="cursor: pointer; font-size: 13px;">View Full Raw Metadata</summary>
<pre style="background: #f0f0f0; padding: 10px; border-radius: 4px; overflow: auto; max-height: 400px; font-size: 11px; margin-top: 10px;"><?= htmlspecialchars(json_encode($campaign, JSON_PRETTY_PRINT)) ?></pre>
</details>
</div>
</details>
<?php endforeach; ?>
<?php else: ?>
<p style="margin-top: 15px;">No campaigns returned from API (check OAuth status and response body above)</p>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (isset($results['debug_all_campaigns_count'])): ?>
<div class="alert alert-info" style="margin-top: 20px;">
<strong>🔍 Debug Info:</strong><br>
Found <?= $results['debug_all_campaigns_count'] ?> total campaigns before filtering<br>
Filtering for Content Scaling Status: "<?= htmlspecialchars($results['debug_status_filter']) ?>"<br>
Campaigns after filtering: <?= $results['debug_filtered_count'] ?>
</div>
<?php endif; ?>
<?php if (isset($results['a1_campaigns']) && !empty($results['a1_campaigns'])): ?>
<h3 style="margin-top: 30px;">Found <?= count($results['a1_campaigns']) ?> Campaigns</h3>
<div class="campaign-grid">
<?php foreach ($results['a1_campaigns'] as $campaign): ?>
<div class="campaign-card <?= (isset($results['selected_campaign']) && $results['selected_campaign']['asset_id'] === $campaign['asset_id']) ? 'selected' : '' ?>"
onclick="selectCampaign('<?= htmlspecialchars($campaign['asset_id']) ?>')">
<h3><?= htmlspecialchars($campaign['campaign_name'] ?? 'Unnamed Campaign') ?></h3>
<p><strong>Campaign ID:</strong> <?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?></p>
<p><strong>Asset ID:</strong> <code style="font-size: 11px;"><?= htmlspecialchars($campaign['asset_id']) ?></code></p>
<p><strong>Brand:</strong> <?= htmlspecialchars($campaign['brand'] ?? 'N/A') ?></p>
<p><strong>Market:</strong> <?= htmlspecialchars($campaign['market'] ?? 'N/A') ?></p>
<p><strong>Content Scaling Status:</strong> <span class="status-badge status-a1"><?= htmlspecialchars($campaign['status'] ?? 'N/A') ?> - Ready for Localization</span></p>
</div>
<?php endforeach; ?>
</div>
<form method="POST" id="select-campaign-form">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="select_campaign_a1">
<input type="hidden" name="campaign_id" id="selected-campaign-id">
<button type="submit" class="btn btn-success" id="select-campaign-btn" disabled>
Select Campaign & Continue
</button>
</form>
<?php endif; ?>
<?php if (isset($results['selected_campaign'])): ?>
<div class="alert alert-info" style="margin-top: 30px;">
<strong>Selected Campaign:</strong>
<?= htmlspecialchars($results['selected_campaign']['campaign_name']) ?>
(<?= htmlspecialchars($results['selected_campaign']['campaign_id']) ?>)
<br>
<small><strong>Asset ID:</strong> <code><?= htmlspecialchars($results['selected_campaign']['asset_id']) ?></code></small>
<br>
<a href="debug_assets.php?action=get_folders&campaign_id=<?= urlencode($results['selected_campaign']['asset_id']) ?>"
target="_blank" style="color: #667eea; font-size: 12px;">
🔍 Debug folder structure for this campaign
</a>
</div>
<form method="POST" style="margin-top: 20px;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="get_master_assets">
<button type="submit" class="btn btn-primary">Get Master Assets</button>
</form>
<?php endif; ?>
<?php if (isset($results['master_assets']) && !empty($results['master_assets'])): ?>
<h3 style="margin-top: 30px;">Master Assets (<?= count($results['master_assets']) ?> files)</h3>
<form method="POST" style="margin: 20px 0;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="download_all_assets">
<button type="submit" class="btn btn-success">📥 Download All Assets</button>
</form>
<div class="asset-list">
<?php foreach ($results['master_assets'] as $index => $asset): ?>
<?php
$assetName = extractFolderName($asset);
$assetId = $asset['asset_id'];
$metadataId = 'metadata-' . $index; // Use index instead of asset_id for simpler ID
?>
<div class="asset-item">
<div class="asset-info">
<strong><?= htmlspecialchars($assetName) ?></strong><br>
<small>ID: <?= htmlspecialchars($assetId) ?></small><br>
<small>Type: <?= htmlspecialchars($asset['mime_type'] ?? 'Unknown') ?></small>
<?php if (isset($asset['file_size'])): ?>
<small> | Size: <?= number_format($asset['file_size']) ?> bytes</small>
<?php endif; ?>
</div>
<div class="asset-actions">
<form method="POST" style="display: inline;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="download_asset">
<input type="hidden" name="asset_id" value="<?= htmlspecialchars($assetId) ?>">
<input type="hidden" name="filename" value="<?= htmlspecialchars($assetName) ?>">
<button type="submit" class="btn btn-success">📥 Download</button>
</form>
<form method="POST" style="display: inline;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="download_asset_metadata">
<input type="hidden" name="asset_id" value="<?= htmlspecialchars($assetId) ?>">
<input type="hidden" name="filename" value="<?= htmlspecialchars($assetName) ?>">
<button type="submit" class="btn btn-secondary">💾 JSON</button>
</form>
<button class="btn btn-secondary"
onclick="toggleMetadata('<?= $metadataId ?>')">
📋 View
</button>
</div>
</div>
<div id="<?= $metadataId ?>" class="metadata-display" style="display: none;">
<?php
$metadata = MetadataExtractor::extractAllMetadata($asset);
if (!empty($metadata)):
?>
<div style="font-size: 13px;">
<!-- Basic Info -->
<?php if (isset($metadata['basic'])): ?>
<div style="background: white; padding: 12px; margin: 8px 0; border-radius: 4px; border-left: 4px solid #667eea;">
<strong>📋 Basic Info:</strong><br>
<div style="margin-top: 8px; display: grid; grid-template-columns: 150px 1fr; gap: 5px;">
<?php foreach ($metadata['basic'] as $key => $value): ?>
<?php if ($value !== null): ?>
<div style="color: #666;"><?= ucwords(str_replace('_', ' ', $key)) ?>:</div>
<div><strong><?= htmlspecialchars($value) ?></strong></div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<!-- Content Info -->
<?php if (isset($metadata['content'])): ?>
<div style="background: white; padding: 12px; margin: 8px 0; border-radius: 4px; border-left: 4px solid #28a745;">
<strong>🖼️ Content Info:</strong><br>
<div style="margin-top: 8px; display: grid; grid-template-columns: 150px 1fr; gap: 5px;">
<?php foreach ($metadata['content'] as $key => $value): ?>
<?php if ($value !== null && $value !== -1): ?>
<div style="color: #666;"><?= ucwords(str_replace('_', ' ', $key)) ?>:</div>
<div><strong><?= is_string($value) ? htmlspecialchars($value) : $value ?></strong></div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<!-- Custom Fields by Category -->
<?php if (isset($metadata['custom_fields'])): ?>
<?php foreach ($metadata['custom_fields'] as $category => $fields): ?>
<?php if (!empty($fields)): ?>
<details style="background: white; padding: 12px; margin: 8px 0; border-radius: 4px; border-left: 4px solid #ffc107;">
<summary style="cursor: pointer; font-weight: 600; color: #333;">
📁 <?= htmlspecialchars($category) ?> (<?= count($fields) ?> fields)
</summary>
<div style="margin-top: 8px; display: grid; grid-template-columns: 200px 1fr; gap: 5px;">
<?php foreach ($fields as $fieldName => $fieldData): ?>
<div style="color: #666; padding-top: 4px;"><?= htmlspecialchars($fieldName) ?>:</div>
<div style="padding-top: 4px;">
<strong>
<?php
if (is_array($fieldData['value'])) {
echo htmlspecialchars(implode(', ', $fieldData['value']));
} else {
echo htmlspecialchars($fieldData['value']);
}
?>
</strong>
</div>
<?php endforeach; ?>
</div>
</details>
<?php endif; ?>
<?php endforeach; ?>
<?php endif; ?>
<!-- Permissions -->
<?php if (isset($metadata['permissions'])): ?>
<details style="background: white; padding: 12px; margin: 8px 0; border-radius: 4px; border-left: 4px solid #dc3545;">
<summary style="cursor: pointer; font-weight: 600; color: #333;">🔐 Permissions</summary>
<div style="margin-top: 8px; columns: 2;">
<?php foreach ($metadata['permissions'] as $perm => $value): ?>
<div style="padding: 2px 0;">
<?= $value ? '✅' : '❌' ?> <?= htmlspecialchars(preg_replace('/Permission$/', '', $perm)) ?>
</div>
<?php endforeach; ?>
</div>
</details>
<?php endif; ?>
<!-- Renditions -->
<?php if (isset($metadata['renditions'])): ?>
<details style="background: white; padding: 12px; margin: 8px 0; border-radius: 4px; border-left: 4px solid #17a2b8;">
<summary style="cursor: pointer; font-weight: 600; color: #333;">🎨 Renditions (<?= count($metadata['renditions']) ?>)</summary>
<div style="margin-top: 8px;">
<?php foreach ($metadata['renditions'] as $rendName => $rendData): ?>
<div style="background: #f8f9fa; padding: 8px; margin: 4px 0; border-radius: 3px;">
<strong><?= htmlspecialchars($rendName) ?></strong><br>
<small>Size: <?= number_format($rendData['content_size'] ?? 0) ?> bytes |
<?= $rendData['width'] ?? 0 ?>x<?= $rendData['height'] ?? 0 ?>px |
<?= htmlspecialchars($rendData['mime_type'] ?? 'N/A') ?></small>
</div>
<?php endforeach; ?>
</div>
</details>
<?php endif; ?>
</div>
<?php else: ?>
<p>No metadata available for this asset</p>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<div style="margin-top: 30px; padding: 20px; background: #fff3cd; border-radius: 8px;">
<h4>⚠️ Update Status to A2</h4>
<p style="margin: 10px 0;">
Once all assets are downloaded (or attempted), update the campaign status to A2
(Selected Master Assets sent to Agency)
</p>
<p style="margin: 10px 0; font-size: 13px; color: #856404;">
<strong>Note:</strong> If files don't exist in storage (test environment), you can still
update the status to test the workflow progression.
</p>
<form method="POST">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="update_status_to_a2">
<button type="submit" class="btn btn-success">Update Status: A1 → A2</button>
</form>
</div>
<?php endif; ?>
<?php if (isset($results['status_update_error'])): ?>
<div class="alert alert-error" style="margin-top: 20px;">
<strong>⚠️ Status Update Debug Information:</strong>
<details style="margin-top: 10px;">
<summary style="cursor: pointer; font-weight: 600;">View detailed error information</summary>
<div style="margin-top: 10px; font-size: 12px; font-family: monospace;">
<div style="background: #f8f9fa; padding: 10px; border-radius: 4px; margin: 5px 0;">
<strong>HTTP Status Code:</strong> <?= htmlspecialchars($results['status_update_error']['http_code']) ?>
</div>
<div style="background: #f8f9fa; padding: 10px; border-radius: 4px; margin: 5px 0;">
<strong>Folder ID:</strong> <?= htmlspecialchars($results['status_update_error']['folder_id']) ?>
</div>
<div style="background: #f8f9fa; padding: 10px; border-radius: 4px; margin: 5px 0;">
<strong>Target Status:</strong> <?= htmlspecialchars($results['status_update_error']['new_status']) ?>
</div>
<?php if (isset($results['status_update_error']['response']['body'])): ?>
<div style="background: #f8f9fa; padding: 10px; border-radius: 4px; margin: 5px 0;">
<strong>API Response Body:</strong>
<pre style="margin-top: 5px; white-space: pre-wrap; word-wrap: break-word;"><?= htmlspecialchars($results['status_update_error']['response']['body']) ?></pre>
</div>
<?php endif; ?>
<?php if (isset($results['status_update_error']['response']['url'])): ?>
<div style="background: #f8f9fa; padding: 10px; border-radius: 4px; margin: 5px 0;">
<strong>Request URL:</strong> <?= htmlspecialchars($results['status_update_error']['response']['url']) ?>
</div>
<?php endif; ?>
</div>
</details>
</div>
<?php endif; ?>
<?php if (isset($results['last_download'])): ?>
<?php $dl = $results['last_download']; ?>
<div class="alert alert-<?= $dl['success'] ? 'success' : 'error' ?>" style="margin-top: 20px;">
<?php if ($dl['success']): ?>
<strong>✅ Download Successful:</strong> <?= htmlspecialchars($dl['filename']) ?>
<br><small>Size: <?= number_format($dl['size']) ?> bytes | Path: <?= htmlspecialchars($dl['filepath']) ?></small>
<?php if (isset($dl['download_method'])): ?>
<br><small>Method: <?= htmlspecialchars($dl['download_method']) ?> | URL: <?= htmlspecialchars($dl['rendition_url'] ?? 'N/A') ?></small>
<?php endif; ?>
<?php else: ?>
<strong>❌ Download Failed:</strong> <?= htmlspecialchars($dl['error']) ?>
<br><small>HTTP Code: <?= $dl['http_code'] ?></small>
<?php if (isset($dl['tried_url'])): ?>
<br><small>Tried URL: <?= htmlspecialchars($dl['tried_url']) ?></small>
<?php endif; ?>
<?php if (isset($dl['debug_message'])): ?>
<br><small>Details: <?= htmlspecialchars($dl['debug_message']) ?></small>
<?php endif; ?>
<?php if (isset($dl['debug_info']) && !empty($dl['debug_info'])): ?>
<br><small>Debug: <?= htmlspecialchars(json_encode($dl['debug_info'])) ?></small>
<?php endif; ?>
<?php if (isset($dl['all_attempts']) && !empty($dl['all_attempts'])): ?>
<details style="margin-top: 10px;">
<summary style="cursor: pointer; font-size: 12px;">View all download attempts (<?= count($dl['all_attempts']) ?>)</summary>
<div style="margin-top: 8px; font-size: 11px;">
<?php foreach ($dl['all_attempts'] as $idx => $att): ?>
<div style="padding: 4px; background: #f8f9fa; margin: 2px 0; border-radius: 3px;">
<?= $idx + 1 ?>. [<?= htmlspecialchars($att['type']) ?>] <?= htmlspecialchars($att['url']) ?>
- HTTP <?= $att['http_code'] ?>
</div>
<?php endforeach; ?>
</div>
</details>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (isset($results['bulk_download'])): ?>
<div class="alert alert-<?= $results['bulk_download']['successful'] === $results['bulk_download']['total'] ? 'success' : 'error' ?>"
style="margin-top: 20px;">
<strong>Bulk Download Results:</strong>
<?= $results['bulk_download']['successful'] ?> of <?= $results['bulk_download']['total'] ?> assets downloaded successfully
<?php if ($results['bulk_download']['failed'] > 0): ?>
<br><small><?= $results['bulk_download']['failed'] ?> files failed (may not exist in storage)</small>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<!-- Upload Workflow Tab -->
<div id="tab-upload" class="tab-content <?= $currentTab === 'upload' ? 'active' : '' ?>">
<h2>📤 Upload Workflow: A2 → A3</h2>
<p style="color: #666; margin: 10px 0 20px 0;">
Load campaigns with status A2 (assets sent to agency), upload processed files, and update status to A3
</p>
<!-- Test Upload Section -->
<div style="background: #fff3cd; border: 2px solid #ffc107; border-radius: 8px; padding: 20px; margin-bottom: 30px;">
<h3 style="color: #856404;">🧪 Test Upload to Specific Folder</h3>
<p style="color: #856404; margin: 10px 0;">
Upload directly to a folder ID for testing (bypasses campaign workflow)
</p>
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="test_upload_to_folder">
<div style="margin: 15px 0;">
<label style="display: block; margin-bottom: 5px; font-weight: 600;">Target Folder ID:</label>
<input type="text" name="test_folder_id"
value="e96080ba0cd1427d253a28a87504b6665eaa02cb"
style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-family: monospace;">
</div>
<div style="margin: 15px 0;">
<label style="display: block; margin-bottom: 5px; font-weight: 600;">Select file to upload:</label>
<input type="file" name="test_upload_file" required
style="padding: 10px; border: 2px solid #ffc107; border-radius: 6px; width: 100%; background: white;">
</div>
<button type="submit" class="btn btn-primary">🧪 Test Upload to This Folder</button>
</form>
<?php if (isset($results['test_upload_result'])): ?>
<?php $tr = $results['test_upload_result']; ?>
<div class="alert alert-<?= $tr['success'] ? 'success' : 'error' ?>" style="margin-top: 20px;">
<?php if ($tr['success']): ?>
<strong>✅ TEST UPLOAD SUCCESSFUL!</strong><br>
Filename: <?= htmlspecialchars($tr['filename']) ?><br>
Asset ID: <?= htmlspecialchars($tr['asset_id'] ?? 'N/A') ?><br>
Folder: <?= htmlspecialchars($results['test_folder_id']) ?>
<?php else: ?>
<strong>❌ Test Upload Failed:</strong> <?= htmlspecialchars($tr['error']) ?><br>
HTTP Code: <?= $tr['http_code'] ?><br>
Folder: <?= htmlspecialchars($results['test_folder_id']) ?>
<?php if (isset($tr['response_body'])): ?>
<details style="margin-top: 10px;">
<summary style="cursor: pointer;">View API Response</summary>
<pre style="font-size: 11px; background: white; padding: 10px; margin-top: 5px;"><?= htmlspecialchars($tr['response_body']) ?></pre>
</details>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<hr style="margin: 30px 0;">
<!-- End Test Upload Section -->
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="load_campaigns_a2">
<button type="submit" class="btn btn-primary">Load Campaigns (Content Scaling Status = A2)</button>
</form>
<?php if (!empty($results) && $currentTab === 'upload'): ?>
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="clear_results" value="1">
<button type="submit" class="btn btn-secondary">🗑️ Clear Workflow Data</button>
</form>
<?php endif; ?>
<?php if (isset($results['a2_campaigns']) && !empty($results['a2_campaigns'])): ?>
<h3 style="margin-top: 30px;">Found <?= count($results['a2_campaigns']) ?> Campaigns</h3>
<div class="campaign-grid">
<?php foreach ($results['a2_campaigns'] as $campaign): ?>
<div class="campaign-card <?= (isset($results['selected_campaign_a2']) && $results['selected_campaign_a2']['asset_id'] === $campaign['asset_id']) ? 'selected' : '' ?>"
onclick="selectCampaignA2('<?= htmlspecialchars($campaign['asset_id']) ?>')">
<h3><?= htmlspecialchars($campaign['campaign_name'] ?? 'Unnamed Campaign') ?></h3>
<p><strong>Campaign ID:</strong> <?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?></p>
<p><strong>Asset ID:</strong> <code style="font-size: 11px;"><?= htmlspecialchars($campaign['asset_id']) ?></code></p>
<p><strong>Brand:</strong> <?= htmlspecialchars($campaign['brand'] ?? 'N/A') ?></p>
<p><strong>Market:</strong> <?= htmlspecialchars($campaign['market'] ?? 'N/A') ?></p>
<p><strong>Content Scaling Status:</strong> <span class="status-badge status-a2"><?= htmlspecialchars($campaign['status'] ?? 'N/A') ?> - Assets Sent to Agency</span></p>
<form method="POST" style="margin-top: 10px;" onclick="event.stopPropagation();">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="reset_to_a1">
<input type="hidden" name="campaign_id" value="<?= htmlspecialchars($campaign['asset_id']) ?>">
<button type="submit" class="btn btn-danger" style="font-size: 12px; padding: 8px 12px;" onclick="return confirm('Reset <?= htmlspecialchars($campaign['campaign_name']) ?> to A1 for testing?')">
🔄 Reset to A1
</button>
</form>
</div>
<?php endforeach; ?>
</div>
<form method="POST" id="select-campaign-a2-form">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="select_campaign_a2">
<input type="hidden" name="campaign_id" id="selected-campaign-a2-id">
<button type="submit" class="btn btn-success" id="select-campaign-a2-btn" disabled>
Select Campaign & Continue
</button>
</form>
<?php endif; ?>
<?php if (isset($results['selected_campaign_a2'])): ?>
<div class="alert alert-info" style="margin-top: 30px;">
<strong>Selected Campaign:</strong>
<?= htmlspecialchars($results['selected_campaign_a2']['campaign_name']) ?>
(<?= htmlspecialchars($results['selected_campaign_a2']['campaign_id']) ?>)
</div>
<?php if (!isset($results['upload_folder_id'])): ?>
<form method="POST" style="margin-top: 20px;">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="get_upload_folder">
<button type="submit" class="btn btn-primary">Find Upload Folder & Get Master Assets Metadata</button>
</form>
<?php endif; ?>
<?php endif; ?>
<?php if (isset($results['upload_folder_id'])): ?>
<div class="alert alert-success" style="margin-top: 20px;">
✅ Upload target folder found
</div>
<h3 style="margin-top: 30px;">Upload Processed Files</h3>
<?php if (isset($results['master_assets_for_upload']) && !empty($results['master_assets_for_upload'])): ?>
<div class="alert alert-success" style="margin-bottom: 20px;">
✅ Found <?= count($results['master_assets_for_upload']) ?> master assets from this campaign
</div>
<div style="background: #f8f9fa; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
<h4>📋 Select Master Asset Metadata to Use:</h4>
<p style="color: #666; margin: 10px 0;">
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.
</p>
<?php foreach ($results['master_assets_for_upload'] as $idx => $masterAsset): ?>
<div style="background: white; border: 2px solid #dee2e6; border-radius: 6px; padding: 15px; margin: 10px 0;">
<label style="display: flex; align-items: center; cursor: pointer;">
<input type="radio" name="selected_master_metadata" value="<?= $idx ?>"
onchange="selectMasterMetadata(<?= $idx ?>)"
<?= $idx === 0 ? 'checked' : '' ?>
style="margin-right: 10px; transform: scale(1.3);">
<div>
<strong><?= htmlspecialchars($masterAsset['name'] ?? 'Unknown') ?></strong><br>
<small>Asset ID: <?= htmlspecialchars($masterAsset['asset_id']) ?></small><br>
<small>Type: <?= htmlspecialchars($masterAsset['mime_type'] ?? 'Unknown') ?></small>
<?php if (isset($masterAsset['metadata_model_id'])): ?>
<br><small style="color: #28a745;">✅ Model: <?= htmlspecialchars($masterAsset['metadata_model_id']) ?></small>
<?php else: ?>
<br><small style="color: #dc3545;">⚠️ No Metadata Model ID</small>
<?php endif; ?>
<?php if (isset($masterAsset['security_policy_list'])): ?>
<br><small style="color: #28a745;">✅ <?= count($masterAsset['security_policy_list']) ?> Security Policies</small>
<?php else: ?>
<br><small style="color: #dc3545;">⚠️ No Security Policies</small>
<?php endif; ?>
</div>
</label>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="alert alert-info" style="margin-bottom: 20px;">
<strong>Note:</strong> No master assets found.
<br>Click "Find Upload Folder" above to fetch master assets from this campaign.
</div>
<?php endif; ?>
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="upload_files">
<input type="hidden" name="master_metadata_index" id="master-metadata-index" value="0">
<div style="background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 20px 0;">
<label style="display: block; margin-bottom: 10px; font-weight: 600;">
Select files to upload:
</label>
<input type="file" name="upload_files[]" multiple
accept=".jpg,.jpeg,.png,.gif,.pdf,.ai,.psd,.eps,.tif,.tiff,.mov,.mp4,.avi,.zip,.txt,.doc,.docx,.xls,.xlsx"
style="padding: 10px; border: 2px dashed #667eea; border-radius: 6px; width: 100%; background: white;">
<p style="font-size: 13px; color: #666; margin-top: 10px;">
Accepted formats: Images (JPG, PNG, GIF, TIFF), Documents (PDF, AI, PSD, EPS), Video (MOV, MP4, AVI), Archives (ZIP), Office (DOC, XLS, TXT)
</p>
</div>
<button type="submit" class="btn btn-success">📤 Upload Files to DAM</button>
</form>
<?php endif; ?>
<?php if (isset($results['upload_debug'])): ?>
<div class="alert alert-info" style="margin-top: 20px;">
<strong>🔍 Upload Debug Info:</strong><br>
<strong>Your File:</strong> <?= htmlspecialchars($results['upload_debug']['upload_filename']) ?>
(<?= htmlspecialchars($results['upload_debug']['upload_detected_mime']) ?>)<br>
<strong>Target Folder ID:</strong> <?= htmlspecialchars($results['upload_debug']['upload_folder_id']) ?><br>
<hr style="margin: 10px 0;">
<strong>Using Metadata From:</strong> <?= htmlspecialchars($results['upload_debug']['selected_master_name']) ?><br>
Master Asset ID: <?= htmlspecialchars($results['upload_debug']['selected_master_asset_id']) ?><br>
Metadata Model ID: <strong><?= htmlspecialchars($results['upload_debug']['metadata_model_id']) ?></strong><br>
Has Security Policies: <?= $results['upload_debug']['has_security_policies'] ?> (<?= $results['upload_debug']['security_policy_count'] ?> policies)<br>
Master MIME Type: <?= htmlspecialchars($results['upload_debug']['master_mime_type']) ?><br>
<hr style="margin: 10px 0;">
<strong>Sending:</strong> asset_representation (model ID + security policies only) + manifest + parent_folder_id + files<br>
<small>Note: Full metadata too large to send - using model ID inheritance instead</small>
</div>
<?php endif; ?>
<?php if (isset($results['upload_results'])): ?>
<?php $ur = $results['upload_results']; ?>
<div class="alert alert-<?= $ur['successful'] > 0 ? 'success' : 'error' ?>" style="margin-top: 20px;">
<strong>Upload Results:</strong>
<?= $ur['successful'] ?> of <?= $ur['total'] ?> files uploaded successfully
<?php if (!empty($ur['details'])): ?>
<details style="margin-top: 15px;">
<summary style="cursor: pointer;">View upload details</summary>
<div style="margin-top: 10px;">
<?php foreach ($ur['details'] as $idx => $detail): ?>
<div style="padding: 8px; margin: 5px 0; background: white; border-radius: 4px;">
<?php if ($detail['success']): ?>
✅ <?= htmlspecialchars($detail['filename']) ?>
<br><small>Asset ID: <?= htmlspecialchars($detail['asset_id'] ?? 'N/A') ?></small>
<?php else: ?>
❌ <?= htmlspecialchars($detail['filename'] ?? 'Unknown') ?>
<br><small style="color: #dc3545;"><strong>Error:</strong> <?= htmlspecialchars($detail['error']) ?></small>
<?php if (isset($detail['http_code'])): ?>
<br><small>HTTP Code: <?= $detail['http_code'] ?></small>
<?php endif; ?>
<?php if (isset($detail['response_body']) && !empty($detail['response_body'])): ?>
<details style="margin-top: 5px;">
<summary style="cursor: pointer; font-size: 11px;">View API Response</summary>
<pre style="font-size: 10px; background: #f8f9fa; padding: 5px; margin-top: 5px; max-height: 200px; overflow: auto;"><?= htmlspecialchars($detail['response_body']) ?></pre>
</details>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</details>
<?php endif; ?>
</div>
<?php if ($ur['successful'] > 0): ?>
<div style="margin-top: 30px; padding: 20px; background: #d4edda; border-radius: 8px;">
<h4>✅ Update Status to A3</h4>
<p style="margin: 10px 0;">
Files have been uploaded. Update the campaign status to A3
(Localized Asset received from Agency)
</p>
<form method="POST">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="update_status_to_a3">
<button type="submit" class="btn btn-success">Update Status: A2 → A3</button>
</form>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
<!-- Rework Workflow Tab -->
<div id="tab-rework" class="tab-content <?= $currentTab === 'rework' ? 'active' : '' ?>">
<h2>🔄 Rework Workflow: A5 → A6</h2>
<p style="color: #666; margin: 10px 0 20px 0;">
Load campaigns with status A5 (rework needed), download assets for rework, and update status to A6
</p>
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="load_campaigns_a5">
<button type="submit" class="btn btn-primary">Load Campaigns (Content Scaling Status = A5)</button>
</form>
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="debug_all_campaigns_rework">
<button type="submit" class="btn btn-secondary">🔍 Debug: Load ALL Campaigns (no filter)</button>
</form>
<?php if (!empty($results) && $currentTab === 'rework'): ?>
<form method="POST" style="display: inline-block;">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="clear_results" value="1">
<button type="submit" class="btn btn-secondary">🗑️ Clear Workflow Data</button>
</form>
<?php endif; ?>
<?php if (isset($results['debug_campaigns_rework']) || isset($results['debug_search_response_rework'])): ?>
<div class="alert alert-<?= ($results['debug_search_response_rework']['http_code'] ?? 0) == 503 ? 'error' : 'info' ?>" style="margin-top: 30px;">
<h3>🔍 Debug Results: Found <?= count($results['debug_campaigns_rework'] ?? []) ?> Campaigns</h3>
<?php if (isset($results['oauth_debug_rework'])): ?>
<p style="font-size: 13px; margin: 10px 0; padding: 10px; background: white; border-radius: 4px;">
<strong>OAuth Status:</strong>
<?= $results['oauth_debug_rework']['has_token'] ? '✅ Token Active' : '❌ No Token' ?> |
Expires: <?= htmlspecialchars($results['oauth_debug_rework']['expires_at']) ?>
</p>
<?php endif; ?>
<?php if (isset($results['debug_search_response_rework'])): ?>
<p style="font-size: 13px; margin: 10px 0; padding: 10px; background: white; border-radius: 4px;">
<strong>API Response:</strong> HTTP <?= $results['debug_search_response_rework']['http_code'] ?>
<?php if ($results['debug_search_response_rework']['http_code'] == 503): ?>
<span style="color: #dc3545; font-weight: bold;">- Service Unavailable</span>
<?php endif; ?>
<br>
<strong>Total results from API:</strong> <?= $results['debug_search_response_rework']['total_results'] ?? 0 ?><br>
<strong>URL:</strong> <code style="font-size: 11px;"><?= htmlspecialchars($results['debug_search_response_rework']['url']) ?></code>
</p>
<?php endif; ?>
<?php if (!empty($results['debug_campaigns_rework'])): ?>
<p>Showing ALL campaigns - use reset button to change any to A5 for testing:</p>
<?php foreach ($results['debug_campaigns_rework'] as $idx => $campaign): ?>
<details style="margin: 15px 0; background: white; padding: 15px; border-radius: 6px;">
<summary style="cursor: pointer; font-weight: 600;">
Campaign <?= $idx + 1 ?>: <?= htmlspecialchars($campaign['campaign_name'] ?? 'Unnamed') ?>
(<?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?>)
- Content Scaling Status: <span class="status-badge status-<?= strtolower($campaign['status'] ?? 'unknown') ?>"><?= htmlspecialchars($campaign['status'] ?? 'NOT FOUND') ?></span>
</summary>
<div style="margin-top: 15px;">
<p><strong>Asset ID:</strong> <?= htmlspecialchars($campaign['asset_id']) ?></p>
<p><strong>Campaign ID:</strong> <?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?></p>
<p><strong>Content Scaling Status:</strong> <?= htmlspecialchars($campaign['status'] ?? 'NOT FOUND') ?></p>
<p><strong>Brand:</strong> <?= htmlspecialchars($campaign['brand'] ?? 'N/A') ?></p>
<p><strong>Market:</strong> <?= htmlspecialchars($campaign['market'] ?? 'N/A') ?></p>
<form method="POST" style="margin-top: 15px; display: inline-block;">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="reset_to_a5">
<input type="hidden" name="campaign_id" value="<?= htmlspecialchars($campaign['asset_id']) ?>">
<button type="submit" class="btn btn-danger" onclick="return confirm('Reset campaign <?= htmlspecialchars($campaign['campaign_name']) ?> to A5 status?')">
🔄 Reset to A5 (for testing)
</button>
</form>
<details style="margin-top: 10px;">
<summary style="cursor: pointer; font-size: 13px;">View Full Raw Metadata</summary>
<pre style="background: #f0f0f0; padding: 10px; border-radius: 4px; overflow: auto; max-height: 400px; font-size: 11px; margin-top: 10px;"><?= htmlspecialchars(json_encode($campaign, JSON_PRETTY_PRINT)) ?></pre>
</details>
</div>
</details>
<?php endforeach; ?>
<?php else: ?>
<p style="margin-top: 15px;">No campaigns returned from API (check OAuth status and response above)</p>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (isset($results['a5_campaigns']) && !empty($results['a5_campaigns'])): ?>
<h3 style="margin-top: 30px;">Found <?= count($results['a5_campaigns']) ?> Campaigns Needing Rework</h3>
<div class="campaign-grid">
<?php foreach ($results['a5_campaigns'] as $campaign): ?>
<div class="campaign-card <?= (isset($results['selected_campaign_a5']) && $results['selected_campaign_a5']['asset_id'] === $campaign['asset_id']) ? 'selected' : '' ?>"
onclick="selectCampaignA5('<?= htmlspecialchars($campaign['asset_id']) ?>')">
<h3><?= htmlspecialchars($campaign['campaign_name'] ?? 'Unnamed Campaign') ?></h3>
<p><strong>Campaign ID:</strong> <?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?></p>
<p><strong>Asset ID:</strong> <code style="font-size: 11px;"><?= htmlspecialchars($campaign['asset_id']) ?></code></p>
<p><strong>Brand:</strong> <?= htmlspecialchars($campaign['brand'] ?? 'N/A') ?></p>
<p><strong>Market:</strong> <?= htmlspecialchars($campaign['market'] ?? 'N/A') ?></p>
<p><strong>Content Scaling Status:</strong> <span class="status-badge status-a5"><?= htmlspecialchars($campaign['status'] ?? 'N/A') ?> - Rework Needed</span></p>
</div>
<?php endforeach; ?>
</div>
<form method="POST" id="select-campaign-a5-form">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="select_campaign_a5">
<input type="hidden" name="campaign_id" id="selected-campaign-a5-id">
<button type="submit" class="btn btn-success" id="select-campaign-a5-btn" disabled>
Select Campaign & Continue
</button>
</form>
<?php endif; ?>
<?php if (isset($results['selected_campaign_a5'])): ?>
<div class="alert alert-info" style="margin-top: 30px;">
<strong>Selected Campaign:</strong>
<?= htmlspecialchars($results['selected_campaign_a5']['campaign_name']) ?>
(<?= htmlspecialchars($results['selected_campaign_a5']['campaign_id']) ?>)
</div>
<form method="POST" style="margin-top: 20px;">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="get_rework_assets">
<button type="submit" class="btn btn-primary">Get Rework Assets</button>
</form>
<?php endif; ?>
<?php if (isset($results['rework_assets']) && !empty($results['rework_assets'])): ?>
<h3 style="margin-top: 30px;">Rework Assets (<?= count($results['rework_assets']) ?> files)</h3>
<form method="POST" style="margin: 20px 0;">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="download_all_rework">
<button type="submit" class="btn btn-success">📥 Download All Rework Assets</button>
</form>
<div class="asset-list">
<?php foreach ($results['rework_assets'] as $index => $asset): ?>
<?php
$assetName = extractFolderName($asset);
$assetId = $asset['asset_id'];
$metadataId = 'rework-metadata-' . $index;
?>
<div class="asset-item">
<div class="asset-info">
<strong><?= htmlspecialchars($assetName) ?></strong><br>
<small>ID: <?= htmlspecialchars($assetId) ?></small><br>
<small>Type: <?= htmlspecialchars($asset['mime_type'] ?? 'Unknown') ?></small>
<?php if (isset($asset['file_size'])): ?>
<small> | Size: <?= number_format($asset['file_size']) ?> bytes</small>
<?php endif; ?>
</div>
<div class="asset-actions">
<form method="POST" style="display: inline;">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="download_rework_asset">
<input type="hidden" name="asset_id" value="<?= htmlspecialchars($assetId) ?>">
<input type="hidden" name="filename" value="<?= htmlspecialchars($assetName) ?>">
<button type="submit" class="btn btn-success">📥 Download</button>
</form>
<button class="btn btn-secondary"
onclick="toggleMetadata('<?= $metadataId ?>')">
📋 Metadata
</button>
</div>
</div>
<div id="<?= $metadataId ?>" class="metadata-display" style="display: none;">
<?php
$metadata = MetadataExtractor::extractAllMetadata($asset);
if (!empty($metadata)):
?>
<div style="font-size: 13px;">
<!-- Same metadata display as download tab -->
<?php if (isset($metadata['basic'])): ?>
<div style="background: white; padding: 12px; margin: 8px 0; border-radius: 4px; border-left: 4px solid #667eea;">
<strong>📋 Basic Info:</strong><br>
<div style="margin-top: 8px; display: grid; grid-template-columns: 150px 1fr; gap: 5px;">
<?php foreach ($metadata['basic'] as $key => $value): ?>
<?php if ($value !== null): ?>
<div style="color: #666;"><?= ucwords(str_replace('_', ' ', $key)) ?>:</div>
<div><strong><?= htmlspecialchars($value) ?></strong></div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
<?php else: ?>
<p>No metadata available for this asset</p>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<div style="margin-top: 30px; padding: 20px; background: #fff3cd; border-radius: 8px;">
<h4>⚠️ Update Status to A6</h4>
<p style="margin: 10px 0;">
Once rework assets are downloaded, update the campaign status to A6
(Assets to be reworked received by the Agency)
</p>
<form method="POST">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="update_status_to_a6">
<button type="submit" class="btn btn-success">Update Status: A5 → A6</button>
</form>
</div>
<?php endif; ?>
<?php if (isset($results['last_rework_download'])): ?>
<?php $dl = $results['last_rework_download']; ?>
<div class="alert alert-<?= $dl['success'] ? 'success' : 'error' ?>" style="margin-top: 20px;">
<?php if ($dl['success']): ?>
<strong>✅ Download Successful:</strong> <?= htmlspecialchars($dl['filename']) ?>
<br><small>Size: <?= number_format($dl['size']) ?> bytes</small>
<?php else: ?>
<strong>❌ Download Failed:</strong> <?= htmlspecialchars($dl['error']) ?>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (isset($results['rework_bulk_download'])): ?>
<div class="alert alert-success" style="margin-top: 20px;">
<strong>Bulk Download Results:</strong>
<?= $results['rework_bulk_download']['successful'] ?> of <?= $results['rework_bulk_download']['total'] ?> rework assets downloaded
</div>
<?php endif; ?>
</div>
</div>
<script>
function switchTab(tabName) {
// Update tabs
document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
event.target.classList.add('active');
document.getElementById('tab-' + tabName).classList.add('active');
// Update URL without reload
const url = new URL(window.location);
url.searchParams.set('tab', tabName);
window.history.pushState({}, '', url);
}
function selectCampaign(campaignId) {
document.querySelectorAll('.campaign-card').forEach(card => {
card.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
document.getElementById('selected-campaign-id').value = campaignId;
document.getElementById('select-campaign-btn').disabled = false;
}
function toggleMetadata(metadataId) {
const metadataDiv = document.getElementById(metadataId);
if (metadataDiv) {
metadataDiv.style.display = metadataDiv.style.display === 'none' ? 'block' : 'none';
}
}
function selectCampaignA2(campaignId) {
document.querySelectorAll('.campaign-card').forEach(card => {
card.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
document.getElementById('selected-campaign-a2-id').value = campaignId;
document.getElementById('select-campaign-a2-btn').disabled = false;
}
function selectCampaignA5(campaignId) {
document.querySelectorAll('.campaign-card').forEach(card => {
card.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
document.getElementById('selected-campaign-a5-id').value = campaignId;
document.getElementById('select-campaign-a5-btn').disabled = false;
}
function selectMasterMetadata(index) {
document.getElementById('master-metadata-index').value = index;
}
</script>
</body>
</html>