Files
virtfusion-whmcs-module/modules/servers/VirtFusionDirect/templates/overview.tpl
Claude c93072b1c6 Enhance VirtFusion WHMCS module with security fixes, new features, and improved UX
Security improvements:
- Enable SSL/TLS certificate verification by default (was disabled, MITM risk)
- Remove error_reporting(0) that silenced all errors
- Add input sanitization on all user parameters (int casting, regex filtering)
- Return proper HTTP status codes (401, 403, 400, 500) instead of always 200
- Add XSS protection with htmlspecialchars and encodeURIComponent
- Add null checks on API response data before property access

New features:
- Power management: boot, shutdown, restart, and force power off controls
- Server rebuild: reinstall with any available OS template from client area
- Server rename: change server display name via PATCH API
- OS template fetching: client-side endpoint for rebuild OS selection
- TestConnection: validate API credentials from WHMCS server settings
- ServiceSingleSignOn: native WHMCS SSO integration for VirtFusion panel
- Server status badge: visual indicator of server state in overview
- Traffic usage display: show bandwidth used vs allocated
- Checkout validation: ShoppingCartValidateCheckout hook ensures OS selection

Ordering process improvements:
- Add default "Select Operating System" placeholder option
- Add "No SSH Key (Optional)" default for SSH dropdown
- Hide SSH key field/container when no keys available
- Wrap hook in try/catch to prevent checkout page breakage
- Sanitize template names with htmlspecialchars
- Use JSON_HEX_* flags for safe script injection

Theme compatibility:
- Properly formatted Smarty templates with readable indentation
- Dual panel/card CSS classes for Bootstrap 3/4/5 compatibility
- Responsive power button layout with mobile breakpoint
- Framework-agnostic HTML that works with Six, Twenty-One, Lagom, and custom themes
- Suspended service state messaging

Code quality:
- Readable, unminified JavaScript with JSDoc header
- Structured CSS with logical section organization
- Improved error messages throughout all provisioning functions
- Added PATCH method support to Curl wrapper
- Added curl error capture on connection failures
- Added connection and request timeouts (10s/30s)
- Fixed memory conversion to check key name instead of display name

Documentation:
- Complete README rewrite with installation, configuration, and troubleshooting guides
- API endpoint reference table
- Configurable options mapping documentation
- Theme override instructions
- Security considerations section

https://claude.ai/code/session_01TCsJ4WZCGuEX3zqh1tQ2zx
2026-02-07 12:18:11 +00:00

224 lines
12 KiB
Smarty

<link href="{$systemURL}modules/servers/VirtFusionDirect/templates/css/module.css" rel="stylesheet">
<script src="{$systemURL}modules/servers/VirtFusionDirect/templates/js/module.js"></script>
{if $serviceStatus eq 'Active'}
{* Server Overview Panel *}
<div class="panel card panel-default mb-3">
<div class="panel-heading card-header">
<h3 class="panel-title card-title m-0">
Server Overview
<span id="vf-status-badge" class="vf-badge" style="float: right;"></span>
</h3>
</div>
<div class="panel-body card-body p-4">
<div id="vf-server-info-loader-container">
<div id="vf-server-info-loader" class="d-flex align-items-center justify-content-center">
<div class="spinner-border"></div>
</div>
</div>
<script>vfServerData('{$serviceid}', '{$systemURL}');</script>
<div id="vf-server-info-error">
<div class="alert alert-warning mb-0">Information unavailable. Try again later.</div>
</div>
<div id="vf-server-info" class="row mb-2">
<div class="col-12">
<div class="row">
<div class="col-md-6">
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">Name:</div>
<div class="col-xs-8 col-8" id="vf-data-server-name"></div>
</div>
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">Hostname:</div>
<div class="col-xs-8 col-8" id="vf-data-server-hostname"></div>
</div>
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">Memory:</div>
<div class="col-xs-8 col-8" id="vf-data-server-memory"></div>
</div>
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">CPU:</div>
<div class="col-xs-8 col-8" id="vf-data-server-cpu"></div>
</div>
</div>
<div class="col-md-6">
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">IPv4:</div>
<div class="col-xs-8 col-8" id="vf-data-server-ipv4"></div>
</div>
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">IPv6:</div>
<div class="col-xs-8 col-8" id="vf-data-server-ipv6"></div>
</div>
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">Storage:</div>
<div class="col-xs-8 col-8" id="vf-data-server-storage"></div>
</div>
<div class="row p-1">
<div class="col-xs-4 col-4 text-right vf-bold">Traffic:</div>
<div class="col-xs-8 col-8">
<span id="vf-data-server-traffic-used"></span>
<span id="vf-data-server-traffic-sep"> / </span>
<span id="vf-data-server-traffic"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{* Power Management Panel *}
<div class="panel card panel-default mb-3">
<div class="panel-heading card-header">
<h3 class="panel-title card-title m-0">Power Management</h3>
</div>
<div class="panel-body card-body p-4">
<div id="vf-power-alert" class="alert" style="display: none;"></div>
<div class="row">
<div class="col-12">
<div class="vf-power-buttons">
<button id="vf-power-boot" onclick="vfPowerAction('{$serviceid}','{$systemURL}','boot')" type="button" class="btn btn-success vf-btn-power">
<span class="vf-btn-spinner spinner-border spinner-border-sm" style="display:none;"></span>
Start
</button>
<button id="vf-power-restart" onclick="vfPowerAction('{$serviceid}','{$systemURL}','restart')" type="button" class="btn btn-warning vf-btn-power">
<span class="vf-btn-spinner spinner-border spinner-border-sm" style="display:none;"></span>
Restart
</button>
<button id="vf-power-shutdown" onclick="vfPowerAction('{$serviceid}','{$systemURL}','shutdown')" type="button" class="btn btn-info vf-btn-power">
<span class="vf-btn-spinner spinner-border spinner-border-sm" style="display:none;"></span>
Shutdown
</button>
<button id="vf-power-poweroff" onclick="vfPowerAction('{$serviceid}','{$systemURL}','poweroff')" type="button" class="btn btn-danger vf-btn-power">
<span class="vf-btn-spinner spinner-border spinner-border-sm" style="display:none;"></span>
Force Off
</button>
</div>
</div>
</div>
</div>
</div>
{* Manage Panel *}
<div class="panel card panel-default mb-3">
<div class="panel-heading card-header">
<h3 class="panel-title card-title m-0">Manage</h3>
</div>
<div class="panel-body card-body p-4">
<div class="row">
<div class="col-12">
<div id="vf-login-error" class="alert alert-danger"></div>
<p>Manage your server via our dedicated control panel. You will be automatically authenticated and the control panel will open in a new window.</p>
<button id="vf-login-button" onclick="vfLoginAsServerOwner('{$serviceid}','{$systemURL}',true)" type="button" class="btn btn-primary text-uppercase d-flex align-items-center">
<div id="vf-login-button-spinner" class="spinner-border spinner-border-sm text-light vf-spinner-margin"></div>
Open Control Panel
</button>
</div>
<div class="col-12">
<p class="mb-0 pt-3 vf-small">Having trouble opening the control panel in a new window? <a href="#" onclick="vfLoginAsServerOwner('{$serviceid}','{$systemURL}',false); return false;">Click here</a> to open in this window.</p>
</div>
{if $serverHostname}
<div class="col-12">
<hr>
<div id="vf-password-reset-error" class="alert alert-danger">Oops! Something went wrong. Try again later.</div>
<div id="vf-password-reset-success" class="alert alert-success">
<div class="mb-2 font-weight-bold">Your new login credentials. These will only be displayed once.</div>
<div class="font-weight-bold">Email: <span class="font-weight-normal" id="vf-data-user-email"></span></div>
<div class="font-weight-bold">Password: <span class="font-weight-normal" id="vf-data-user-password"></span></div>
</div>
<p class="pt-0">Alternatively you may directly access the control panel at <a target="_blank" href="https://{$serverHostname|escape:'htmlall'}">{$serverHostname|escape:'htmlall'}</a></p>
<button id="vf-password-reset-button" onclick="vfUserPasswordReset('{$serviceid}','{$systemURL}')" type="button" class="btn btn-primary text-uppercase d-flex align-items-center">
<div id="vf-password-reset-button-spinner" class="spinner-border spinner-border-sm text-light vf-spinner-margin"></div>
Reset Login Credentials
</button>
</div>
{/if}
</div>
</div>
</div>
{* Rebuild Panel *}
<div class="panel card panel-default mb-3">
<div class="panel-heading card-header">
<h3 class="panel-title card-title m-0">Rebuild Server</h3>
</div>
<div class="panel-body card-body p-4">
<div id="vf-rebuild-alert" class="alert" style="display: none;"></div>
<div class="alert alert-warning">
<strong>Warning:</strong> Rebuilding your server will erase all data on the server and reinstall the operating system. This action cannot be undone.
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group mb-3">
<label for="vf-rebuild-os">Operating System</label>
<select id="vf-rebuild-os" class="form-control">
<option value="">Loading...</option>
</select>
</div>
</div>
</div>
<button id="vf-rebuild-button" onclick="vfRebuildServer('{$serviceid}','{$systemURL}')" type="button" class="btn btn-danger text-uppercase d-flex align-items-center">
<span id="vf-rebuild-spinner" class="spinner-border spinner-border-sm vf-spinner-margin" style="display:none;"></span>
Rebuild Server
</button>
<script>vfLoadOsTemplates('{$serviceid}', '{$systemURL}');</script>
</div>
</div>
{elseif $serviceStatus eq 'Suspended'}
<div class="panel card panel-default mb-3">
<div class="panel-heading card-header">
<h3 class="panel-title card-title m-0">Service Suspended</h3>
</div>
<div class="panel-body card-body p-4">
<div class="alert alert-danger mb-0">
Your service is currently suspended. Please contact support or pay any outstanding invoices to restore access.
</div>
</div>
</div>
{/if}
{* Billing Overview - Always visible *}
<div class="panel card panel-default mb-3">
<div class="panel-heading card-header">
<h3 class="panel-title card-title m-0">Billing Overview</h3>
</div>
<div class="panel-body card-body">
<div class="row">
<div class="col-lg-6">
<div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">Product:</div>
<div class="col-xs-6 col-6">{$groupname} - {$product}</div>
</div>
<div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.recurringamount}:</div>
<div class="col-xs-6 col-6">{$recurringamount}</div>
</div>
<div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.orderbillingcycle}:</div>
<div class="col-xs-6 col-6">{$billingcycle}</div>
</div>
</div>
<div class="col-lg-6">
<div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.clientareahostingregdate}:</div>
<div class="col-xs-6 col-6">{$regdate}</div>
</div>
<div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.clientareahostingnextduedate}:</div>
<div class="col-xs-6 col-6">{$nextduedate}</div>
</div>
<div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.orderpaymentmethod}:</div>
<div class="col-xs-6 col-6">{$paymentmethod}</div>
</div>
</div>
</div>
</div>
</div>