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>
543 lines
No EOL
23 KiB
PHP
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>
|