1145 lines
49 KiB
PHP
1145 lines
49 KiB
PHP
<?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';
|
||
|
||
$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 '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();
|
||
?>
|
||
<!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 with Status A1</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['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><span class="status-badge status-a1">A1 - 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>
|
||
<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;">
|
||
<!-- 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['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, upload processed assets, and update status to A3
|
||
</p>
|
||
|
||
<form method="POST">
|
||
<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 with Status A2</button>
|
||
</form>
|
||
|
||
<div class="alert alert-info" style="margin-top: 20px;">
|
||
<strong>ℹ️ Coming Soon:</strong> Upload functionality will be implemented in next phase
|
||
</div>
|
||
</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">
|
||
<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 with Status A5</button>
|
||
</form>
|
||
|
||
<div class="alert alert-info" style="margin-top: 20px;">
|
||
<strong>ℹ️ Coming Soon:</strong> Rework workflow will be implemented in next phase
|
||
</div>
|
||
</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';
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|