mirror of
https://gitlab.com/ArkHost/WHMCS-ArkHost-HetznerVPS.git
synced 2026-07-24 07:45:53 +02:00
v1.2.1-fix
This commit is contained in:
@@ -345,11 +345,11 @@ function ArkHostHetznerVPS_API(array $params) {
|
||||
break;
|
||||
|
||||
case 'Create backup':
|
||||
// Use snapshots
|
||||
// Create manual backup (still type=backup, but with distinct description)
|
||||
$url .= 'servers/' . ArkHostHetznerVPS_GetVPSID($params) . '/actions/create_image';
|
||||
$method = 'POST';
|
||||
$data = array(
|
||||
'description' => 'Backup created on ' . date('Y-m-d H:i:s'),
|
||||
'description' => 'Manual backup - ' . date('Y-m-d H:i:s'),
|
||||
'type' => 'backup'
|
||||
);
|
||||
break;
|
||||
@@ -1540,35 +1540,8 @@ function ArkHostHetznerVPS_ClientAreaAPI(array $params) {
|
||||
// Check backup permissions
|
||||
$backupActions = array('Create backup', 'Delete backup', 'Restore backup');
|
||||
if (in_array($action, $backupActions)) {
|
||||
// Check if backups are enabled either via module settings or configurable options
|
||||
$backupsEnabled = false;
|
||||
|
||||
// Check module product settings
|
||||
if (isset($params['backups']) && $params['backups'] == 'on') {
|
||||
$backupsEnabled = true;
|
||||
}
|
||||
|
||||
// Check configurable options
|
||||
if (isset($params['configoptions']['Backups']) && $params['configoptions']['Backups'] == 'Yes') {
|
||||
$backupsEnabled = true;
|
||||
}
|
||||
|
||||
// If not enabled in WHMCS settings, check if backups are actually enabled on Hetzner's side
|
||||
if (!$backupsEnabled) {
|
||||
try {
|
||||
$serverInfoParams = $params;
|
||||
$serverInfoParams['action'] = 'Server Info';
|
||||
$serverInfoResult = ArkHostHetznerVPS_API($serverInfoParams);
|
||||
|
||||
// Check if the server has backups enabled (indicated by backup_window being set)
|
||||
if (isset($serverInfoResult['server']['backup_window']) && $serverInfoResult['server']['backup_window'] !== null) {
|
||||
$backupsEnabled = true;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// If we can't check, assume not enabled
|
||||
$backupsEnabled = false;
|
||||
}
|
||||
}
|
||||
// Check if backups are enabled in module settings
|
||||
$backupsEnabled = (ArkHostHetznerVPS_GetOption($params, 'backups') === 'on');
|
||||
|
||||
if (!$backupsEnabled) {
|
||||
return array('jsonResponse' => array(
|
||||
@@ -1805,7 +1778,8 @@ function ArkHostHetznerVPS_ClientAreaAPI(array $params) {
|
||||
'name' => $image['description'] ?? $image['name'],
|
||||
'created' => $image['created'],
|
||||
'size' => isset($image['image_size']) ? round($image['image_size'], 2) : 0, // Already in GB from API
|
||||
'type' => $image['type']
|
||||
'type' => $image['type'],
|
||||
'status' => $image['status'] ?? 'available' // Include status from Hetzner API
|
||||
);
|
||||
$backupIndex++;
|
||||
}
|
||||
@@ -2260,17 +2234,32 @@ function ArkHostHetznerVPS_ClientArea(array $params) {
|
||||
// Process operating system info for Hetzner
|
||||
if (isset($serverInfo['image']) && !empty($operatingSystemsTemp['images'])) {
|
||||
$osId = $serverInfo['image']['name'];
|
||||
$osName = strtolower($serverInfo['image']['description'] ?? $osId);
|
||||
|
||||
// Find matching OS in available images
|
||||
$imageType = $serverInfo['image']['type'] ?? 'system';
|
||||
|
||||
// If this is a backup or snapshot image, try to get the actual OS info from os_flavor/os_version
|
||||
if (($imageType === 'backup' || $imageType === 'snapshot') && isset($serverInfo['image']['os_flavor'])) {
|
||||
// Use os_flavor and os_version to construct a meaningful OS name
|
||||
$osName = strtolower($serverInfo['image']['os_flavor']);
|
||||
$displayName = ucfirst($serverInfo['image']['os_flavor']);
|
||||
if (isset($serverInfo['image']['os_version']) && !empty($serverInfo['image']['os_version'])) {
|
||||
$displayName .= ' ' . $serverInfo['image']['os_version'];
|
||||
}
|
||||
} else {
|
||||
$osName = strtolower($serverInfo['image']['description'] ?? $osId);
|
||||
$displayName = $serverInfo['image']['description'] ?? $osId;
|
||||
}
|
||||
|
||||
// Find matching OS in available images (only for system images)
|
||||
$currentOS = null;
|
||||
foreach ($operatingSystemsTemp['images'] as $os) {
|
||||
if ($os['name'] === $osId) {
|
||||
$currentOS = $os;
|
||||
break;
|
||||
if ($imageType === 'system') {
|
||||
foreach ($operatingSystemsTemp['images'] as $os) {
|
||||
if ($os['name'] === $osId) {
|
||||
$currentOS = $os;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($currentOS) {
|
||||
$displayName = $currentOS['description'] ?? $currentOS['name'];
|
||||
$osName = strtolower($displayName);
|
||||
@@ -2308,10 +2297,15 @@ function ArkHostHetznerVPS_ClientArea(array $params) {
|
||||
'image' => isset($operatingSystems[$group]) ? $operatingSystems[$group]['image'] : 'data:image/png;base64,' . base64_encode(file_get_contents($dirOS . (in_array($imageFile, $availableOS) ? $imageFile : 'others') . '.png'))
|
||||
);
|
||||
} else {
|
||||
// Fallback if OS not found - use image info from server
|
||||
$displayName = $serverInfo['image']['description'] ?? $osId;
|
||||
$osName = strtolower($displayName);
|
||||
|
||||
// Fallback if OS not found - already have $displayName and $osName from above
|
||||
// Just ensure they are set
|
||||
if (!isset($displayName)) {
|
||||
$displayName = $serverInfo['image']['description'] ?? $osId;
|
||||
}
|
||||
if (!isset($osName)) {
|
||||
$osName = strtolower($displayName);
|
||||
}
|
||||
|
||||
// Try to determine OS type from name
|
||||
if (strpos($osName, 'alma') !== false) {
|
||||
$imageFile = 'almalinux';
|
||||
@@ -2407,9 +2401,21 @@ function ArkHostHetznerVPS_ClientArea(array $params) {
|
||||
$serverInfo['bandwidth'] = 20480; // 20TB in GB (20 * 1024)
|
||||
$serverInfo['bandwidth_used'] = 0; // Not available via API
|
||||
|
||||
// Add datacenter info
|
||||
$serverInfo['datacenter'] = isset($serverInfo['datacenter']['description']) ? $serverInfo['datacenter']['description'] : 'N/A';
|
||||
$serverInfo['location'] = isset($serverInfo['datacenter']['location']['city']) ? $serverInfo['datacenter']['location']['city'] : 'N/A';
|
||||
// Add datacenter info - format as "City, Country"
|
||||
$city = isset($serverInfo['datacenter']['location']['city']) ? $serverInfo['datacenter']['location']['city'] : '';
|
||||
$country = isset($serverInfo['datacenter']['location']['country']) ? $serverInfo['datacenter']['location']['country'] : '';
|
||||
|
||||
if ($city && $country) {
|
||||
$serverInfo['datacenter'] = $city . ', ' . $country;
|
||||
} elseif ($city) {
|
||||
$serverInfo['datacenter'] = $city;
|
||||
} elseif ($country) {
|
||||
$serverInfo['datacenter'] = $country;
|
||||
} else {
|
||||
$serverInfo['datacenter'] = 'N/A';
|
||||
}
|
||||
|
||||
$serverInfo['location'] = $city ?: 'N/A';
|
||||
|
||||
// Get root password with expiration check (72 hours)
|
||||
$passwordSetTime = $params['model']->serviceProperties->get('ArkHostHetznerVPS|Password Set Time');
|
||||
@@ -2431,8 +2437,8 @@ function ArkHostHetznerVPS_ClientArea(array $params) {
|
||||
$serverInfo['install_root'] = '';
|
||||
}
|
||||
|
||||
// For now, always show backups tab - the API will handle permissions
|
||||
$backupsEnabled = true;
|
||||
// Check if backups are enabled in module settings
|
||||
$backupsEnabled = (ArkHostHetznerVPS_GetOption($params, 'backups') === 'on');
|
||||
|
||||
return array(
|
||||
'templatefile' => 'template/clientarea_direct',
|
||||
@@ -2443,6 +2449,7 @@ function ArkHostHetznerVPS_ClientArea(array $params) {
|
||||
'token' => generate_token('plain'),
|
||||
'ADDONLANG' => ArkHostHetznerVPS_Translation(),
|
||||
'backupsEnabled' => $backupsEnabled,
|
||||
'productName' => $params['productname'] ?? $params['configoption1'] ?? 'VPS',
|
||||
)
|
||||
);
|
||||
} catch (Exception $err) {
|
||||
|
||||
@@ -69,7 +69,7 @@ $_ADDONLANG['Overview']['ResourceAllocation'] = 'Resource Allocation';
|
||||
$_ADDONLANG['Overview']['QuickActions'] = 'Quick Actions';
|
||||
$_ADDONLANG['Overview']['Hostname'] = 'Hostname';
|
||||
$_ADDONLANG['Overview']['Status'] = 'Status';
|
||||
$_ADDONLANG['Overview']['OS'] = 'Operating System';
|
||||
$_ADDONLANG['Overview']['OS'] = 'OS';
|
||||
$_ADDONLANG['Overview']['Location'] = 'Location';
|
||||
$_ADDONLANG['Overview']['CPU_Cores'] = 'vCPU Cores';
|
||||
$_ADDONLANG['Overview']['Memory'] = 'Memory';
|
||||
@@ -143,7 +143,7 @@ $_ADDONLANG['Settings']['Password']['Submit'] = 'Reset Password';
|
||||
### Reinstall
|
||||
$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Reinstall';
|
||||
$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Please understand that by reinstalling, all the data will be wiped from the server. This action is irreversible!';
|
||||
$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Operating System';
|
||||
$_ADDONLANG['Settings']['Reinstall']['OS'] = 'OS';
|
||||
$_ADDONLANG['Settings']['Reinstall']['Version'] = 'CHOOSE VERSION';
|
||||
$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Reinstall';
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted">{$ADDONLANG.Overview.ServerType}:</td>
|
||||
<td><strong>{$serverInfo['server_type']['description']|default:$ADDONLANG.ServerTypes.Standard}</strong></td>
|
||||
<td><strong>{$productName}</strong></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -521,8 +521,10 @@ function updateBackupTable(data) {
|
||||
backupDate = backupDate.split('T')[0];
|
||||
}
|
||||
|
||||
// Determine backup type
|
||||
var backupType = backup.type === 'backup' ? lang.backups.automatic : lang.backups.manual;
|
||||
// Determine backup type based on description
|
||||
// Manual backups have descriptions starting with "Manual backup -"
|
||||
var backupName = backup.name || '';
|
||||
var backupType = backupName.indexOf('Manual backup -') === 0 ? lang.backups.manual : lang.backups.automatic;
|
||||
|
||||
// Format size (already in GB from API)
|
||||
var sizeStr = 'N/A';
|
||||
@@ -530,22 +532,40 @@ function updateBackupTable(data) {
|
||||
sizeStr = backup.size + ' ' + lang.general.gb;
|
||||
}
|
||||
|
||||
// Status is always available for Hetzner backups
|
||||
var statusBadge = '<span class="badge badge-success">' + lang.backups.available + '</span>';
|
||||
// Determine status badge based on size first (more reliable than API status)
|
||||
var statusBadge;
|
||||
if (!backup.size || backup.size === 0 || backup.size === '0') {
|
||||
// Backup is still being created (size not available yet)
|
||||
statusBadge = '<span class="badge badge-warning">' + lang.backups.creating + '</span>';
|
||||
} else if (backup.status === 'available' || backup.size > 0) {
|
||||
// Backup is ready (has a size)
|
||||
statusBadge = '<span class="badge badge-success">' + lang.backups.available + '</span>';
|
||||
} else if (backup.status === 'creating') {
|
||||
// Status says creating but has size (unlikely but possible)
|
||||
statusBadge = '<span class="badge badge-warning">' + lang.backups.creating + '</span>';
|
||||
} else {
|
||||
// Other statuses (error, etc)
|
||||
statusBadge = '<span class="badge badge-danger">' + (backup.status || lang.backups.error) + '</span>';
|
||||
}
|
||||
|
||||
// Use backup ID for Hetzner
|
||||
var backupId = backup.id || backup.file;
|
||||
|
||||
row.innerHTML =
|
||||
|
||||
// Disable buttons if backup is still being created (size not available)
|
||||
var isCreating = (!backup.size || backup.size === 0 || backup.size === '0');
|
||||
var disabledAttr = isCreating ? ' disabled' : '';
|
||||
var disabledClass = isCreating ? ' disabled' : '';
|
||||
|
||||
row.innerHTML =
|
||||
'<td>' + backupDate + '</td>' +
|
||||
'<td>' + sizeStr + '</td>' +
|
||||
'<td>' + backupType + '</td>' +
|
||||
'<td>' + statusBadge + '</td>' +
|
||||
'<td style="white-space: nowrap;">' +
|
||||
'<button class="btn btn-xs btn-primary mr-1" style="padding: 4px 8px; font-size: 12px;" onclick="restoreBackup(\'' + backupId + '\'); return false;" title="' + lang.restore + '">' +
|
||||
'<button class="btn btn-xs btn-primary mr-1' + disabledClass + '" style="padding: 4px 8px; font-size: 12px;" onclick="restoreBackup(\'' + backupId + '\'); return false;" title="' + lang.restore + '"' + disabledAttr + '>' +
|
||||
'<i class="fa fa-undo"></i>' +
|
||||
'</button>' +
|
||||
'<button class="btn btn-xs btn-danger" style="padding: 4px 8px; font-size: 12px;" onclick="deleteBackup(\'' + backupId + '\'); return false;" title="' + lang.delete + '">' +
|
||||
'<button class="btn btn-xs btn-danger' + disabledClass + '" style="padding: 4px 8px; font-size: 12px;" onclick="deleteBackup(\'' + backupId + '\'); return false;" title="' + lang.delete + '"' + disabledAttr + '>' +
|
||||
'<i class="fa fa-trash"></i>' +
|
||||
'</button>' +
|
||||
'</td>';
|
||||
|
||||
@@ -68,6 +68,21 @@
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.arkhost-vps-container .btn-danger {
|
||||
background: linear-gradient(135deg, #dc3545 0%, #c82333 100%) !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
padding: 10px 20px;
|
||||
border-radius: 12px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 8px rgba(220, 53, 69, 0.3);
|
||||
}
|
||||
.arkhost-vps-container .btn-danger:hover {
|
||||
background: linear-gradient(135deg, #c82333 0%, #bd2130 100%) !important;
|
||||
box-shadow: 0 4px 12px rgba(220, 53, 69, 0.5) !important;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.arkhost-vps-container .head {
|
||||
border-bottom: 2px solid #3c7fb4;
|
||||
margin-bottom: 20px;
|
||||
|
||||
Reference in New Issue
Block a user