feat: major enhancement — OS gallery, server rename, traffic chart, backups, VNC toggle, password reset, Redis caching, UX improvements

- Remove client IP removal capability (keep backend methods removed too)
- Add copy-to-clipboard buttons for IP addresses with tooltip feedback
- Replace OS dropdown with tile gallery (grouped, searchable, brand colors, EOL badges) in rebuild panel and checkout page
- Add inline server rename with friendly name generator and RFC 1123 validation
- Add traffic statistics canvas chart with responsive resize in resources panel
- Add backup listing timeline in manage panel with show-all expansion
- Add VNC enable/disable toggle with connection details and password copy
- Add server root password reset with auto-clipboard copy (never displayed)
- Add skeleton loading placeholders, action cooldowns (power 3s, rebuild 30s), progress indicator with elapsed timer
- Sanitize all client-facing error messages (no raw API errors exposed)
- Convert all state-mutating AJAX calls from GET to POST
- Add explicit break after all output() calls in client.php
- Add Redis-backed API response caching (Cache.php): OS templates 10min, traffic/backups 2min, currencies 30min, packages 10min
- Add GitHub Actions workflow for weekly VirtFusion API change detection
- Move cache busting step after semantic-release in publish workflow
- Add endpoint doc generator script and OpenAPI baseline placeholder
- Improve hostname generation entropy (bin2hex random_bytes)
- Add .superpowers/ to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Prophet731
2026-03-19 05:40:32 -05:00
parent 538974e0fe
commit 90a97c4afb
13 changed files with 1647 additions and 249 deletions

View File

@@ -26,6 +26,12 @@ class ConfigureService extends Module
*/
public function fetchPackageId(string $packageName): ?int
{
$cacheKey = 'pkg_name:' . md5($packageName);
$cached = Cache::get($cacheKey);
if ($cached !== null) {
return $cached;
}
if (!$this->cp) return null;
$request = $this->initCurl($this->cp['token']);
@@ -38,6 +44,7 @@ class ConfigureService extends Module
foreach ($packages['data'] as $package) {
if ($package['name'] === $packageName && $package['enabled'] === true) {
Cache::set($cacheKey, $package['id'], 600);
return $package['id'];
}
}
@@ -72,6 +79,12 @@ class ConfigureService extends Module
return null;
}
$cacheKey = 'tpl:' . $serverPackageId;
$cached = Cache::get($cacheKey);
if ($cached !== null) {
return $cached;
}
if (!$this->cp) return null;
$request = $this->initCurl($this->cp['token']);
@@ -80,7 +93,9 @@ class ConfigureService extends Module
sprintf("%s/media/templates/fromServerPackageSpec/%d", $this->cp['url'], $serverPackageId)
);
return $this->decodeResponseFromJson($response);
$result = $this->decodeResponseFromJson($response);
Cache::set($cacheKey, $result, 600);
return $result;
}
/**
@@ -139,8 +154,8 @@ class ConfigureService extends Module
$request = $this->initCurl($this->cp['token']);
// Generate a random 8 character hostname
$hostname = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 8);
// Generate a hostname with sufficient entropy to avoid collisions
$hostname = 'vps-' . bin2hex(random_bytes(4));
$sshKeyValue = $vars['customfields']['Initial SSH Key'] ?? null;
$sshKeyId = null;