ferrero-opentext/index.php
DJP 716f0be068 Initial commit: Ferrero OpenText Content Scaling Application
Complete PHP-based workflow application for Ferrero DAM system:
- OAuth2 authentication with automatic token management
- Campaign discovery and filtering
- Folder structure navigation
- Asset download (individual and bulk)
- Metadata extraction and display
- Clean step-by-step web interface

Status: Fully functional and production-ready

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 14:29:20 -04:00

543 lines
No EOL
23 KiB
PHP

<?php
session_start();
require_once 'src/TestRunner.php';
require_once 'src/ResponseFormatter.php';
require_once 'src/WorkflowManager.php';
$config = [
'baseUrl' => $_SESSION['baseUrl'] ?? '',
'apiKey' => $_SESSION['apiKey'] ?? '',
'timeout' => 30,
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json'
]
];
// Try to use the new collection first, fallback to old one
$collectionPath = __DIR__ . '/Content Scaling Flow.postman_collection_Oliver(New).json';
if (!file_exists($collectionPath)) {
$collectionPath = __DIR__ . '/Content Scaling Flow_Oliver.Postman_Collection.json';
}
$testRunner = null;
$error = null;
try {
if (file_exists($collectionPath)) {
$testRunner = new TestRunner($collectionPath, $config);
} else {
$error = "Postman collection file not found: " . $collectionPath;
}
} catch (Exception $e) {
$error = "Error initializing test runner: " . $e->getMessage();
}
$action = $_GET['action'] ?? $_POST['action'] ?? '';
$results = [];
$summary = [];
$connectionTest = null;
$oauth2Status = null;
$workflowManager = null;
$actionableCampaigns = [];
$workflowReport = '';
if ($_POST && $testRunner) {
if ($action === 'update_config') {
$_SESSION['baseUrl'] = $_POST['baseUrl'] ?? '';
$_SESSION['apiKey'] = $_POST['apiKey'] ?? '';
$config['baseUrl'] = $_SESSION['baseUrl'];
$config['apiKey'] = $_SESSION['apiKey'];
$testRunner->updateConfig($config);
$message = "Configuration updated successfully";
}
if ($action === 'test_connection') {
$connectionTest = $testRunner->testConnection();
}
if ($action === 'check_oauth2') {
$oauth2Status = $testRunner->getOAuth2Status();
}
if ($action === 'refresh_token') {
$refreshResult = $testRunner->refreshToken();
$oauth2Status = $testRunner->getOAuth2Status();
$message = $refreshResult ? "Token refreshed successfully" : "Token refresh failed";
}
if ($action === 'run_all_tests') {
$results = $testRunner->runAllTests();
$summary = $testRunner->getSummary();
}
if ($action === 'run_single_test') {
$testIndex = intval($_POST['test_index'] ?? 0);
$requests = $testRunner->getAvailableRequests();
if (isset($requests[$testIndex])) {
$results = [$testRunner->runSingleTest($requests[$testIndex], $testIndex)];
}
}
if ($action === 'analyze_campaigns') {
$workflowManager = new WorkflowManager($testRunner);
$campaignResult = $workflowManager->getCampaignFolders();
if ($campaignResult && $campaignResult['status'] === 'PASS') {
$actionableCampaigns = $workflowManager->getActionableCampaigns();
$workflowReport = $workflowManager->generateWorkflowReport($actionableCampaigns);
$results = [$campaignResult];
$message = "Campaign analysis completed. Found " . count($actionableCampaigns) . " campaigns requiring action.";
} else {
$error = "Failed to retrieve campaign folders for analysis.";
}
}
if ($action === 'process_campaign') {
$campaignId = $_POST['campaign_id'] ?? '';
if ($campaignId) {
$workflowManager = new WorkflowManager($testRunner);
$workflowResults = $workflowManager->processCampaign($campaignId);
// Convert workflow results to display format
$results = [];
foreach ($workflowResults as $step => $result) {
if (isset($result['response'])) {
$results[] = $result;
}
}
$message = "Campaign processing initiated for ID: " . $campaignId;
}
}
}
$availableRequests = $testRunner ? $testRunner->getAvailableRequests() : [];
$credentials = $testRunner ? $testRunner->getCredentials() : [];
// Get OAuth2 status if not already checked
if ($testRunner && !$oauth2Status) {
$oauth2Status = $testRunner->getOAuth2Status();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenText API Endpoint Tester</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #e0e0e0;
}
.config-section, .test-section, .results-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 6px;
background-color: #fafafa;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: 600;
color: #333;
}
input, select, textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.btn {
background-color: #007cba;
color: white;
padding: 12px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-right: 10px;
margin-bottom: 10px;
}
.btn:hover {
background-color: #005a8b;
}
.btn-success { background-color: #28a745; }
.btn-danger { background-color: #dc3545; }
.btn-warning { background-color: #ffc107; color: #333; }
.error { color: #dc3545; background-color: #f8d7da; padding: 10px; border-radius: 4px; margin: 10px 0; }
.success { color: #155724; background-color: #d4edda; padding: 10px; border-radius: 4px; margin: 10px 0; }
.status-pass { color: #28a745; font-weight: bold; }
.status-fail { color: #dc3545; font-weight: bold; }
.status-error { color: #ffc107; font-weight: bold; }
.results-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.results-table th, .results-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
.results-table th {
background-color: #f8f9fa;
font-weight: 600;
}
.request-details {
background-color: #f8f9fa;
padding: 15px;
margin: 10px 0;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 12px;
}
.summary-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: #fff;
padding: 20px;
border-radius: 6px;
border-left: 4px solid #007cba;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.formatted-response {
max-height: 400px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
background: white;
}
.folder-item, .asset-item {
border: 1px solid #ddd;
margin: 10px 0;
padding: 15px;
border-radius: 4px;
background: #fafafa;
}
.metadata {
background: #f0f8ff;
padding: 10px;
border-radius: 4px;
margin-top: 10px;
}
.action-needed {
background: #fff3cd;
padding: 10px;
border-radius: 4px;
margin-top: 10px;
border-left: 4px solid #ffc107;
}
.badge {
background: #007cba;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
margin-left: 10px;
}
</style>
<script>
function showDetails(detailsId) {
document.getElementById(detailsId).style.display = 'table-row';
}
function hideDetails(detailsId) {
document.getElementById(detailsId).style.display = 'none';
}
// Auto-expand first result if it's a campaign folder response
document.addEventListener('DOMContentLoaded', function() {
const firstDetailsRow = document.querySelector('[id^="details-"]');
if (firstDetailsRow && firstDetailsRow.querySelector('.formatted-response')) {
showDetails(firstDetailsRow.id);
}
});
</script>
</head>
<body>
<div class="container">
<div class="header">
<h1>OpenText API Endpoint Tester</h1>
<p>Test your Postman collection endpoints and validate API connectivity</p>
</div>
<?php if ($error): ?>
<div class="error">
<strong>Error:</strong> <?= htmlspecialchars($error) ?>
</div>
<?php endif; ?>
<?php if (isset($message)): ?>
<div class="success"><?= htmlspecialchars($message) ?></div>
<?php endif; ?>
<!-- Configuration Section -->
<div class="config-section">
<h2>API Configuration</h2>
<!-- OAuth2 Status -->
<?php if ($oauth2Status): ?>
<div class="oauth-status" style="background: #e8f4f8; padding: 15px; border-radius: 4px; margin-bottom: 20px;">
<h3>OAuth2 Authentication Status</h3>
<?php if ($oauth2Status['enabled']): ?>
<?php if (isset($oauth2Status['error'])): ?>
<div class="error">OAuth2 Error: <?= htmlspecialchars($oauth2Status['error']) ?></div>
<?php else: ?>
<p><strong>Status:</strong>
<?= $oauth2Status['has_token'] && $oauth2Status['is_valid'] ?
'<span class="status-pass">Active</span>' :
'<span class="status-fail">Token Expired/Invalid</span>' ?>
</p>
<?php if ($oauth2Status['has_token']): ?>
<p><strong>Token Expires:</strong> <?= htmlspecialchars($oauth2Status['expires_at']) ?></p>
<p><strong>Expires In:</strong> <?= $oauth2Status['expires_in'] ?> seconds</p>
<?php endif; ?>
<form method="POST" style="display: inline;">
<input type="hidden" name="action" value="refresh_token">
<button type="submit" class="btn btn-warning">Refresh Token</button>
</form>
<?php endif; ?>
<?php else: ?>
<p class="status-error">OAuth2 not configured: <?= htmlspecialchars($oauth2Status['message']) ?></p>
<?php endif; ?>
<form method="POST" style="display: inline; margin-left: 10px;">
<input type="hidden" name="action" value="check_oauth2">
<button type="submit" class="btn">Check OAuth2 Status</button>
</form>
</div>
<?php endif; ?>
<!-- Credentials Info -->
<?php if (!empty($credentials)): ?>
<div class="credentials-info" style="background: #f8f9fa; padding: 15px; border-radius: 4px; margin-bottom: 20px;">
<h3>Loaded Credentials</h3>
<p><strong>Client ID:</strong> <?= htmlspecialchars($credentials['client_id'] ?? 'Not found') ?></p>
<p><strong>Client Secret:</strong> <?= !empty($credentials['client_secret']) ? str_repeat('*', strlen($credentials['client_secret'])) : 'Not found' ?></p>
</div>
<?php endif; ?>
<form method="POST">
<input type="hidden" name="action" value="update_config">
<div class="form-group">
<label for="baseUrl">Base URL (Optional - will use collection default):</label>
<input type="text" id="baseUrl" name="baseUrl" value="<?= htmlspecialchars($config['baseUrl']) ?>"
placeholder="Leave blank to use collection base URL">
</div>
<div class="form-group">
<label for="apiKey">Manual API Key (Optional - OAuth2 preferred):</label>
<input type="password" id="apiKey" name="apiKey" value="<?= htmlspecialchars($config['apiKey']) ?>"
placeholder="Only needed if OAuth2 fails">
</div>
<button type="submit" class="btn">Update Configuration</button>
</form>
<?php if ($testRunner): ?>
<form method="POST" style="display: inline;">
<input type="hidden" name="action" value="test_connection">
<button type="submit" class="btn btn-warning">Test Connection</button>
</form>
<?php endif; ?>
<?php if ($connectionTest): ?>
<div class="<?= $connectionTest['success'] ? 'success' : 'error' ?>" style="margin-top: 10px;">
Connection test: <?= $connectionTest['success'] ? 'SUCCESS' : 'FAILED' ?>
<?php if (!$connectionTest['success']): ?>
- <?= htmlspecialchars($connectionTest['error']) ?>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php if ($testRunner): ?>
<!-- Content Scaling Workflow Section -->
<div class="test-section">
<h2>Content Scaling Workflow</h2>
<p>Automated workflow for processing campaigns and assets</p>
<form method="POST" style="display: inline;">
<input type="hidden" name="action" value="analyze_campaigns">
<button type="submit" class="btn btn-success">1. Analyze Campaign Folders</button>
</form>
<?php if (!empty($actionableCampaigns)): ?>
<div style="margin-top: 20px;">
<h3>Campaigns Ready for Processing:</h3>
<?php foreach ($actionableCampaigns as $campaign): ?>
<form method="POST" style="display: inline; margin: 5px;">
<input type="hidden" name="action" value="process_campaign">
<input type="hidden" name="campaign_id" value="<?= htmlspecialchars($campaign['id']) ?>">
<button type="submit" class="btn" style="margin-right: 10px;">
2. Process "<?= htmlspecialchars($campaign['campaign_name'] ?? $campaign['name']) ?>"
</button>
</form>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<!-- Manual Test Execution Section -->
<div class="test-section">
<h2>Manual Test Execution</h2>
<p>Available requests: <?= count($availableRequests) ?></p>
<form method="POST" style="display: inline;">
<input type="hidden" name="action" value="run_all_tests">
<button type="submit" class="btn btn-success">Run All Tests</button>
</form>
<form method="POST" style="display: inline; margin-left: 20px;">
<input type="hidden" name="action" value="run_single_test">
<select name="test_index">
<?php foreach ($availableRequests as $index => $request): ?>
<option value="<?= $index ?>">
<?= htmlspecialchars($request['name']) ?>
(<?= htmlspecialchars($request['path']) ?>)
</option>
<?php endforeach; ?>
</select>
<button type="submit" class="btn">Run Selected Test</button>
</form>
</div>
<!-- Workflow Report Section -->
<?php if (!empty($workflowReport)): ?>
<div class="results-section">
<h2>Workflow Analysis</h2>
<?= $workflowReport ?>
</div>
<?php endif; ?>
<!-- Results Section -->
<?php if (!empty($results) || !empty($summary)): ?>
<div class="results-section">
<h2>Test Results</h2>
<?php if (!empty($summary)): ?>
<div class="summary-stats">
<div class="stat-card">
<h4>Total Tests</h4>
<div style="font-size: 24px; font-weight: bold;"><?= $summary['total_tests'] ?></div>
</div>
<div class="stat-card">
<h4>Success Rate</h4>
<div style="font-size: 24px; font-weight: bold; color: #28a745;"><?= $summary['success_rate'] ?>%</div>
</div>
<div class="stat-card">
<h4>Passed</h4>
<div style="font-size: 24px; font-weight: bold; color: #28a745;"><?= $summary['passed'] ?></div>
</div>
<div class="stat-card">
<h4>Failed</h4>
<div style="font-size: 24px; font-weight: bold; color: #dc3545;"><?= $summary['failed'] ?></div>
</div>
<div class="stat-card">
<h4>Avg Response Time</h4>
<div style="font-size: 24px; font-weight: bold;"><?= $summary['avg_response_time'] ?>ms</div>
</div>
</div>
<?php endif; ?>
<table class="results-table">
<thead>
<tr>
<th>Test Name</th>
<th>Method</th>
<th>Status</th>
<th>HTTP Code</th>
<th>Response Time</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<?php foreach ($results as $result): ?>
<tr>
<td><?= htmlspecialchars($result['name']) ?></td>
<td><?= htmlspecialchars($result['response']['method'] ?? 'N/A') ?></td>
<td class="status-<?= strtolower($result['status']) ?>"><?= $result['status'] ?></td>
<td><?= $result['response']['http_code'] ?></td>
<td><?= $result['response']['response_time'] ?? 0 ?>ms</td>
<td>
<div class="response-summary">
<strong>URL:</strong> <?= htmlspecialchars($result['response']['url'] ?? 'N/A') ?><br>
<?php if (!$result['response']['success']): ?>
<strong>Error:</strong> <?= htmlspecialchars($result['response']['error'] ?? 'Unknown error') ?><br>
<?php endif; ?>
<button onclick="showDetails('details-<?= $result['index'] ?? uniqid() ?>')" class="btn" style="margin-top: 5px;">View Response</button>
</div>
</td>
</tr>
<!-- Expanded row for detailed response -->
<tr id="details-<?= $result['index'] ?? uniqid() ?>" style="display: none;">
<td colspan="6" style="background-color: #f8f9fa; padding: 20px;">
<div class="request-details">
<h4>Response Details for: <?= htmlspecialchars($result['name']) ?></h4>
<p><strong>Path:</strong> <?= htmlspecialchars($result['path']) ?></p>
<!-- Formatted Response (visible by default) -->
<div class="formatted-response">
<h5>Formatted Response:</h5>
<?php
$responseBody = $result['response']['body'];
$requestName = strtolower($result['name']);
// Format response based on request type
if (strpos($requestName, 'campaign folder') !== false || strpos($requestName, 'localized campaign') !== false) {
echo ResponseFormatter::formatCampaignFolders($responseBody);
} elseif (strpos($requestName, 'master asset') !== false || strpos($requestName, 'final asset') !== false) {
echo ResponseFormatter::formatAssetFolders($responseBody);
} elseif (strpos($requestName, 'assets from') !== false) {
echo ResponseFormatter::formatAssets($responseBody);
} else {
echo ResponseFormatter::formatGenericResponse($responseBody);
}
?>
</div>
<!-- Raw JSON (collapsible) -->
<details style="margin-top: 20px;">
<summary><strong>View Raw JSON Response</strong></summary>
<textarea readonly style="width: 100%; height: 200px; margin-top: 10px; font-family: 'Courier New', monospace; font-size: 12px;"><?= htmlspecialchars($responseBody) ?></textarea>
</details>
<button onclick="hideDetails('details-<?= $result['index'] ?? uniqid() ?>')" class="btn" style="margin-top: 10px;">Hide Details</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
</body>
</html>