- DB: add usernames/sudo_usernames columns to vm_requests table - create.php: add form inputs for usernames and sudo_usernames - send.php: capture, validate, and store both fields in DB - netbox_integration/netbox_api.php: pass custom_fields to NetBox VM API - requests.php: show usernames/sudo_usernames in request list
161 lines
7.8 KiB
PHP
161 lines
7.8 KiB
PHP
<?php
|
|
require __DIR__ . '/config.php';
|
|
require_login();
|
|
|
|
/* ---- Pagination ---- */
|
|
$page = max(1, (int) ($_GET['page'] ?? 1));
|
|
$perPage = 12;
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$totalStmt = db()->query('SELECT COUNT(*) FROM vm_requests');
|
|
$total = (int) $totalStmt->fetchColumn();
|
|
$totalPages = max(1, (int) ceil($total / $perPage));
|
|
if ($page > $totalPages) $page = $totalPages;
|
|
|
|
$stmt = db()->prepare(
|
|
'SELECT id, vm_name, domain_name, size, vcpus, ram_gb, disk_gb, status, description, usernames, sudo_usernames, created_at, netbox_device_id
|
|
FROM vm_requests
|
|
ORDER BY created_at DESC
|
|
LIMIT :limit OFFSET :offset'
|
|
);
|
|
$stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
$recentRequests = $stmt->fetchAll();
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>My Requests</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="/style.css">
|
|
</head>
|
|
<body>
|
|
<main class="shop-page">
|
|
<nav class="topbar">
|
|
<div>
|
|
<p class="eyebrow">Infrastructure Portal</p>
|
|
<a href="/index.php" style="text-decoration:none;color:inherit;">
|
|
<h1>VM Shop</h1>
|
|
</a>
|
|
</div>
|
|
<div class="nav-links">
|
|
<a href="/index.php" class="nav-link">Shop</a>
|
|
<a href="/requests.php" class="nav-link active">My Requests</a>
|
|
<a class="link-button" href="/logout.php">← Logout</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<?php if (!empty($_GET['cancelled'])): ?>
|
|
<div class="success-message">✓ VM request cancelled.</div>
|
|
<?php endif; ?>
|
|
|
|
<section class="panel requests-panel">
|
|
<div class="requests-header">
|
|
<h2 style="margin:0">My VM Requests</h2>
|
|
<a href="/index.php" class="btn btn-primary btn-sm">+ New Request</a>
|
|
</div>
|
|
|
|
<?php if (!$recentRequests): ?>
|
|
<div class="empty-state">
|
|
<div class="empty-state-icon">🚀</div>
|
|
<p class="muted">No VM requests yet.<br><a href="/index.php">Order your first VM →</a></p>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Domain</th>
|
|
<th>Specs</th>
|
|
<th>Status</th>
|
|
<th>When</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($recentRequests as $request): ?>
|
|
<tr>
|
|
<td>
|
|
<strong><?= h($request['vm_name']) ?></strong>
|
|
<?php if (!empty($request['description'])): ?>
|
|
<div class="muted" style="font-size:0.75rem;margin-top:2px;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="<?= h($request['description']) ?>">
|
|
<?= h($request['description']) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if (!empty($request['usernames'])): ?>
|
|
<div style="font-size:0.75rem;margin-top:3px;color:var(--text-secondary);">
|
|
Users: <strong><?= h($request['usernames']) ?></strong>
|
|
<?php if (!empty($request['sudo_usernames'])): ?>
|
|
<span style="color:var(--warning-text);font-weight:600;">| sudo: <?= h($request['sudo_usernames']) ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td><?= h($request['domain_name']) ?></td>
|
|
<td>
|
|
<span class="badge badge-<?= h($request['size']) ?>" style="font-size:0.7rem;padding:2px 8px;">
|
|
<?= h(ucfirst($request['size'])) ?>
|
|
</span>
|
|
<span class="muted" style="font-size:0.78rem;margin-left:6px;">
|
|
<?= h((string) $request['vcpus']) ?>c / <?= h((string) $request['ram_gb']) ?>G
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span class="badge badge-<?= h($request['status']) ?>">
|
|
<span class="badge-dot"></span>
|
|
<?= h(ucfirst(str_replace('_', ' ', $request['status']))) ?>
|
|
</span>
|
|
</td>
|
|
<td class="td-timestamp">
|
|
<?= h(date('M j, Y', strtotime($request['created_at']))) ?>
|
|
<br>
|
|
<span style="opacity:0.6"><?= h(date('g:i A', strtotime($request['created_at']))) ?></span>
|
|
</td>
|
|
<td class="td-actions">
|
|
<?php if ($request['status'] === 'queued'): ?>
|
|
<form action="/cancel.php" method="post" style="display:inline" onsubmit="return confirm('Cancel this request?');">
|
|
<input type="hidden" name="csrf_token" value="<?= h(csrf_token()) ?>">
|
|
<input type="hidden" name="id" value="<?= (int) $request['id'] ?>">
|
|
<button type="submit" class="cancel-btn" title="Cancel request">Cancel</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php if ($request['netbox_device_id']): ?>
|
|
<tr style="background:var(--success-bg)">
|
|
<td colspan="6" style="font-size:0.78rem;color:var(--success-text);padding-top:4px;padding-bottom:8px;">
|
|
✅ NetBox Device #<?= h((string) $request['netbox_device_id']) ?>
|
|
</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php if ($totalPages > 1): ?>
|
|
<nav class="pagination" aria-label="Requests pagination">
|
|
<?php if ($page > 1): ?>
|
|
<a class="pagination-link" href="/requests.php?page=<?= $page - 1 ?>">← Prev</a>
|
|
<?php else: ?>
|
|
<span class="pagination-link disabled">← Prev</span>
|
|
<?php endif; ?>
|
|
<span class="pagination-info">Page <?= $page ?> of <?= $totalPages ?> (<?= $total ?> total)</span>
|
|
<?php if ($page < $totalPages): ?>
|
|
<a class="pagination-link" href="/requests.php?page=<?= $page + 1 ?>">Next →</a>
|
|
<?php else: ?>
|
|
<span class="pagination-link disabled">Next →</span>
|
|
<?php endif; ?>
|
|
</nav>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</section>
|
|
</main>
|
|
</body>
|
|
</html>
|