Compare commits
15 Commits
1dc84aa5eb
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e80c1430f | |||
| d69c465c92 | |||
| aba2ecf4aa | |||
| df28fc0018 | |||
| 7a578db677 | |||
| 771409e396 | |||
| 6441a8636d | |||
| 6a49489b73 | |||
| a5c20dc834 | |||
| 6056a29865 | |||
| a20e429456 | |||
| a1c3a5a07e | |||
| f4bd50c1b1 | |||
| 7143d721fb | |||
| fe9223a617 |
@@ -152,6 +152,38 @@ if (isset($_POST['execute'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'create_client':
|
||||||
|
if (Profile::canCurrentUser(CREATE)) {
|
||||||
|
$link = ServerAsset::getLinkForAsset($itemtype, $items_id, false);
|
||||||
|
if ($link !== null) {
|
||||||
|
$server = new \GlpiPlugin\Urbackup\Server();
|
||||||
|
$server->getFromDB((int) $link['plugin_urbackup_servers_id']);
|
||||||
|
$client_name = ServerAsset::getAssetName($itemtype, $items_id);
|
||||||
|
try {
|
||||||
|
$api = new \GlpiPlugin\Urbackup\UrbackupApiClient($server);
|
||||||
|
$api->addClient($client_name);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'delete_client':
|
||||||
|
if (Profile::canCurrentUser(PURGE)) {
|
||||||
|
$link = ServerAsset::getLinkForAsset($itemtype, $items_id, false);
|
||||||
|
if ($link !== null) {
|
||||||
|
$server = new \GlpiPlugin\Urbackup\Server();
|
||||||
|
$server->getFromDB((int) $link['plugin_urbackup_servers_id']);
|
||||||
|
$client_name = ServerAsset::getAssetName($itemtype, $items_id);
|
||||||
|
try {
|
||||||
|
$api = new \GlpiPlugin\Urbackup\UrbackupApiClient($server);
|
||||||
|
$api->removeClient($client_name);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'set_internet_mode':
|
case 'set_internet_mode':
|
||||||
if (Profile::canCurrentUser(UPDATE)) {
|
if (Profile::canCurrentUser(UPDATE)) {
|
||||||
$enabled = (int) ($_POST['internet_mode'] ?? 0) === 1;
|
$enabled = (int) ($_POST['internet_mode'] ?? 0) === 1;
|
||||||
|
|||||||
+60
-20
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use GlpiPlugin\Urbackup\Profile;
|
use GlpiPlugin\Urbackup\Profile;
|
||||||
use GlpiPlugin\Urbackup\Server;
|
use GlpiPlugin\Urbackup\Server;
|
||||||
use Html;
|
use GlpiPlugin\Urbackup\ServerAsset;
|
||||||
|
|
||||||
if (!defined('GLPI_ROOT')) {
|
if (!defined('GLPI_ROOT')) {
|
||||||
define('GLPI_ROOT', dirname(__DIR__, 4));
|
define('GLPI_ROOT', dirname(__DIR__, 4));
|
||||||
@@ -17,6 +17,18 @@ if (!Profile::canCurrentUser(UPDATE)) {
|
|||||||
$server = new Server();
|
$server = new Server();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
if (isset($_POST['link_asset'])) {
|
||||||
|
$itemtype = (string) ($_POST['itemtype'] ?? '');
|
||||||
|
$items_id = (int) ($_POST['items_id'] ?? 0);
|
||||||
|
$server_id = (int) ($_POST['id'] ?? 0);
|
||||||
|
|
||||||
|
if ($itemtype !== '' && $items_id > 0 && $server_id > 0) {
|
||||||
|
ServerAsset::connectAssetToServer($itemtype, $items_id, $server_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Html::redirect(PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php?id=' . $server_id);
|
||||||
|
}
|
||||||
|
|
||||||
$id = $_POST['id'] ?? 0;
|
$id = $_POST['id'] ?? 0;
|
||||||
|
|
||||||
if ($id > 0) {
|
if ($id > 0) {
|
||||||
@@ -39,26 +51,54 @@ Html::header(
|
|||||||
'GlpiPlugin\Urbackup\Server'
|
'GlpiPlugin\Urbackup\Server'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($ID > 0) {
|
||||||
|
$server->getFromDB($ID);
|
||||||
|
?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-2">
|
||||||
|
<ul class="nav nav-pills flex-column">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" data-bs-toggle="tab" href="#tab-server">
|
||||||
|
<?php echo htmlspecialchars(__('Server')); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-bs-toggle="tab" href="#tab-linked">
|
||||||
|
<?php echo htmlspecialchars(__('Linked clients', 'urbackup')); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-bs-toggle="tab" href="#tab-unlinked">
|
||||||
|
<?php echo htmlspecialchars(__('Unlinked clients', 'urbackup')); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-bs-toggle="tab" href="#tab-missing">
|
||||||
|
<?php echo htmlspecialchars(__('Missing clients', 'urbackup')); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="tab-server">
|
||||||
|
<?php $server->showForm($ID); ?>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab-linked">
|
||||||
|
<?php Server::showLinkedClientsTab($server); ?>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab-unlinked">
|
||||||
|
<?php Server::showUnlinkedClientsTab($server); ?>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab-missing">
|
||||||
|
<?php Server::showMissingClientsTab($server); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
$server->showForm($ID);
|
$server->showForm($ID);
|
||||||
|
|
||||||
if ($ID > 0 && $server->getFromDB($ID)) {
|
|
||||||
echo '<div class="card mt-4">';
|
|
||||||
echo '<div class="card-header">';
|
|
||||||
echo '<h5 class="mb-0">' . htmlspecialchars(__('Linked clients', 'urbackup')) . '</h5>';
|
|
||||||
echo '</div>';
|
|
||||||
echo '<div class="card-body">';
|
|
||||||
Server::showLinkedClientsTab($server);
|
|
||||||
echo '</div>';
|
|
||||||
echo '</div>';
|
|
||||||
|
|
||||||
echo '<div class="card mt-4">';
|
|
||||||
echo '<div class="card-header">';
|
|
||||||
echo '<h5 class="mb-0">' . htmlspecialchars(__('Unlinked clients', 'urbackup')) . '</h5>';
|
|
||||||
echo '</div>';
|
|
||||||
echo '<div class="card-body">';
|
|
||||||
Server::showUnlinkedClientsTab($server);
|
|
||||||
echo '</div>';
|
|
||||||
echo '</div>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Html::footer();
|
Html::footer();
|
||||||
+34
-30
@@ -116,8 +116,6 @@ class AssetTab extends CommonDBTM
|
|||||||
*/
|
*/
|
||||||
private static function showNoServerLinkedBlock(CommonDBTM $item): void
|
private static function showNoServerLinkedBlock(CommonDBTM $item): void
|
||||||
{
|
{
|
||||||
$asset_location_id = LocationHelper::getAssetLocationId($item);
|
|
||||||
$root_location_id = LocationHelper::getRootLocationIdForAsset($item);
|
|
||||||
$is_sub_location = LocationHelper::assetIsInSubLocation($item);
|
$is_sub_location = LocationHelper::assetIsInSubLocation($item);
|
||||||
$servers = LocationHelper::getAvailableServersForAsset($item);
|
$servers = LocationHelper::getAvailableServersForAsset($item);
|
||||||
|
|
||||||
@@ -128,16 +126,6 @@ class AssetTab extends CommonDBTM
|
|||||||
echo "<table class='tab_cadre_fixe'>";
|
echo "<table class='tab_cadre_fixe'>";
|
||||||
echo "<tr><th colspan='2'>" . htmlspecialchars(__('UrBackup server selection', 'urbackup')) . "</th></tr>";
|
echo "<tr><th colspan='2'>" . htmlspecialchars(__('UrBackup server selection', 'urbackup')) . "</th></tr>";
|
||||||
|
|
||||||
echo "<tr class='tab_bg_1'>";
|
|
||||||
echo "<td>" . htmlspecialchars(__('Asset location ID', 'urbackup')) . "</td>";
|
|
||||||
echo "<td>" . htmlspecialchars((string) $asset_location_id) . "</td>";
|
|
||||||
echo "</tr>";
|
|
||||||
|
|
||||||
echo "<tr class='tab_bg_1'>";
|
|
||||||
echo "<td>" . htmlspecialchars(__('Root location ID', 'urbackup')) . "</td>";
|
|
||||||
echo "<td>" . htmlspecialchars((string) $root_location_id) . "</td>";
|
|
||||||
echo "</tr>";
|
|
||||||
|
|
||||||
if ($is_sub_location) {
|
if ($is_sub_location) {
|
||||||
echo "<tr class='tab_bg_1'>";
|
echo "<tr class='tab_bg_1'>";
|
||||||
echo "<td colspan='2'><em>";
|
echo "<td colspan='2'><em>";
|
||||||
@@ -336,15 +324,36 @@ class AssetTab extends CommonDBTM
|
|||||||
): void {
|
): void {
|
||||||
echo "<div class='plugin-urbackup-inner-tabs'>";
|
echo "<div class='plugin-urbackup-inner-tabs'>";
|
||||||
|
|
||||||
echo "<h3>" . htmlspecialchars(__('State', 'urbackup')) . "</h3>";
|
echo '<ul class="nav nav-tabs" id="urbackupTabs">';
|
||||||
|
echo '<li class="nav-item">';
|
||||||
|
echo '<a class="nav-link active" id="state-tab" data-bs-toggle="tab" href="#state" role="tab">';
|
||||||
|
echo htmlspecialchars(__('State', 'urbackup'));
|
||||||
|
echo '</a></li>';
|
||||||
|
echo '<li class="nav-item">';
|
||||||
|
echo '<a class="nav-link" id="actions-tab" data-bs-toggle="tab" href="#actions" role="tab">';
|
||||||
|
echo htmlspecialchars(__('Actions', 'urbackup'));
|
||||||
|
echo '</a></li>';
|
||||||
|
echo '<li class="nav-item">';
|
||||||
|
echo '<a class="nav-link" id="logs-tab" data-bs-toggle="tab" href="#logs" role="tab">';
|
||||||
|
echo htmlspecialchars(__('Info / Log', 'urbackup'));
|
||||||
|
echo '</a></li>';
|
||||||
|
echo '</ul>';
|
||||||
|
|
||||||
|
echo '<div class="tab-content">';
|
||||||
|
|
||||||
|
echo '<div class="tab-pane fade show active" id="state" role="tabpanel">';
|
||||||
self::showStateSection($server, $link, $api_data);
|
self::showStateSection($server, $link, $api_data);
|
||||||
|
echo '</div>';
|
||||||
|
|
||||||
echo "<h3>" . htmlspecialchars(__('Actions', 'urbackup')) . "</h3>";
|
echo '<div class="tab-pane fade" id="actions" role="tabpanel">';
|
||||||
self::showActionsSection($item, $server, $link, $api_data);
|
self::showActionsSection($item, $server, $link, $api_data);
|
||||||
|
echo '</div>';
|
||||||
|
|
||||||
echo "<h3>" . htmlspecialchars(__('Info / Log', 'urbackup')) . "</h3>";
|
echo '<div class="tab-pane fade" id="logs" role="tabpanel">';
|
||||||
self::showInfoLogSection($api_data);
|
self::showInfoLogSection($api_data);
|
||||||
|
echo '</div>';
|
||||||
|
|
||||||
|
echo '</div>';
|
||||||
echo "</div>";
|
echo "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,17 +427,6 @@ class AssetTab extends CommonDBTM
|
|||||||
|
|
||||||
echo "</table>";
|
echo "</table>";
|
||||||
|
|
||||||
echo '<details class="mt-2" style="cursor:pointer;color:#666;font-size:0.85em">';
|
|
||||||
echo '<summary>' . htmlspecialchars(__('API raw data (debug)', 'urbackup')) . '</summary>';
|
|
||||||
echo '<pre style="max-height:300px;overflow:auto;background:#f5f5f5;padding:8px;border:1px solid #ddd;font-size:0.8em">';
|
|
||||||
echo "--- client_settings ---\n\n";
|
|
||||||
echo htmlspecialchars(json_encode($settings, JSON_PRETTY_PRINT));
|
|
||||||
echo "\n\n--- client_status ---\n\n";
|
|
||||||
echo htmlspecialchars(json_encode($status, JSON_PRETTY_PRINT));
|
|
||||||
echo "\n\n--- recent_backups ---\n\n";
|
|
||||||
echo htmlspecialchars(json_encode($api_data['recent_backups'] ?? [], JSON_PRETTY_PRINT));
|
|
||||||
echo '</pre>';
|
|
||||||
echo '</details>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -488,10 +486,20 @@ class AssetTab extends CommonDBTM
|
|||||||
echo "<tr class='tab_bg_1'>";
|
echo "<tr class='tab_bg_1'>";
|
||||||
echo "<td>" . htmlspecialchars(__('Backup commands', 'urbackup')) . "</td>";
|
echo "<td>" . htmlspecialchars(__('Backup commands', 'urbackup')) . "</td>";
|
||||||
echo "<td>";
|
echo "<td>";
|
||||||
|
echo "<div style='display:flex;gap:24px'>";
|
||||||
|
echo "<div>";
|
||||||
|
echo "<strong>" . htmlspecialchars(__('File backup', 'urbackup')) . "</strong><br>";
|
||||||
self::showActionButton($item, 'incremental_file_backup', __('Incremental file backup', 'urbackup'), 'btn btn-secondary');
|
self::showActionButton($item, 'incremental_file_backup', __('Incremental file backup', 'urbackup'), 'btn btn-secondary');
|
||||||
|
echo "<br>";
|
||||||
self::showActionButton($item, 'full_file_backup', __('Full file backup', 'urbackup'), 'btn btn-secondary');
|
self::showActionButton($item, 'full_file_backup', __('Full file backup', 'urbackup'), 'btn btn-secondary');
|
||||||
|
echo "</div>";
|
||||||
|
echo "<div>";
|
||||||
|
echo "<strong>" . htmlspecialchars(__('Image backup', 'urbackup')) . "</strong><br>";
|
||||||
self::showActionButton($item, 'incremental_image_backup', __('Incremental image backup', 'urbackup'), 'btn btn-secondary');
|
self::showActionButton($item, 'incremental_image_backup', __('Incremental image backup', 'urbackup'), 'btn btn-secondary');
|
||||||
|
echo "<br>";
|
||||||
self::showActionButton($item, 'full_image_backup', __('Full image backup', 'urbackup'), 'btn btn-secondary');
|
self::showActionButton($item, 'full_image_backup', __('Full image backup', 'urbackup'), 'btn btn-secondary');
|
||||||
|
echo "</div>";
|
||||||
|
echo "</div>";
|
||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
|
|
||||||
@@ -707,10 +715,6 @@ class AssetTab extends CommonDBTM
|
|||||||
|
|
||||||
echo "<textarea name='default_dirs' rows='4' cols='80'>" . htmlspecialchars($display) . "</textarea><br>";
|
echo "<textarea name='default_dirs' rows='4' cols='80'>" . htmlspecialchars($display) . "</textarea><br>";
|
||||||
|
|
||||||
echo '<div style="color:#999;font-size:0.8em">';
|
|
||||||
echo 'raw: ' . htmlspecialchars(json_encode($raw));
|
|
||||||
echo '</div>';
|
|
||||||
|
|
||||||
echo Html::submit(__('Save'), [
|
echo Html::submit(__('Save'), [
|
||||||
'name' => 'execute',
|
'name' => 'execute',
|
||||||
'class' => 'btn btn-primary',
|
'class' => 'btn btn-primary',
|
||||||
|
|||||||
@@ -88,16 +88,14 @@ class AssetController
|
|||||||
|
|
||||||
case 'set_internet_mode':
|
case 'set_internet_mode':
|
||||||
if (Profile::canCurrentUser(UPDATE)) {
|
if (Profile::canCurrentUser(UPDATE)) {
|
||||||
$internet_mode = (int) $request->request->get('internet_mode', 0);
|
$enabled = (int) $request->request->get('internet_mode', 0) === 1;
|
||||||
$serverAsset = new ServerAsset();
|
|
||||||
$link = ServerAsset::getLinkForAsset($itemtype, $items_id, true);
|
$link = ServerAsset::getLinkForAsset($itemtype, $items_id, true);
|
||||||
if ($link) {
|
if ($link) {
|
||||||
$server = new Server();
|
$server = new Server();
|
||||||
if ($server->getFromDB((int) $link['plugin_urbackup_servers_id'])) {
|
if ($server->getFromDB((int) $link['plugin_urbackup_servers_id'])) {
|
||||||
$api = new UrbackupApiClient($server);
|
$api = new UrbackupApiClient($server);
|
||||||
$client_name = (string) ($item->fields['name'] ?? '');
|
$client_name = (string) ($item->fields['name'] ?? '');
|
||||||
$setting_key = $api->getInternetModeSettingKey();
|
$api->saveInternetMode($client_name, $enabled);
|
||||||
$api->changeClientSetting($client_name, $setting_key, $internet_mode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+333
-8
@@ -12,9 +12,12 @@ use CommonDBTM;
|
|||||||
use CommonGLPI;
|
use CommonGLPI;
|
||||||
use Dropdown;
|
use Dropdown;
|
||||||
use Entity;
|
use Entity;
|
||||||
|
use Group;
|
||||||
use Html;
|
use Html;
|
||||||
use Location;
|
use Location;
|
||||||
use Session;
|
use Session;
|
||||||
|
use State;
|
||||||
|
use User;
|
||||||
|
|
||||||
class Server extends CommonDBTM
|
class Server extends CommonDBTM
|
||||||
{
|
{
|
||||||
@@ -324,7 +327,14 @@ class Server extends CommonDBTM
|
|||||||
|
|
||||||
$this->initForm($ID, $options);
|
$this->initForm($ID, $options);
|
||||||
$this->showFormHeader($options);
|
$this->showFormHeader($options);
|
||||||
|
$this->showFormFields($ID);
|
||||||
|
$this->showFormButtons($options);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showFormFields(int $ID): void
|
||||||
|
{
|
||||||
echo "<tr class='tab_bg_1'>";
|
echo "<tr class='tab_bg_1'>";
|
||||||
echo "<td>" . htmlspecialchars(__('Name')) . "</td>";
|
echo "<td>" . htmlspecialchars(__('Name')) . "</td>";
|
||||||
echo "<td>";
|
echo "<td>";
|
||||||
@@ -479,10 +489,6 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->showFormButtons($options);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -789,7 +795,6 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
echo '<thead>';
|
echo '<thead>';
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<th>' . htmlspecialchars(__('Asset', 'urbackup')) . '</th>';
|
echo '<th>' . htmlspecialchars(__('Asset', 'urbackup')) . '</th>';
|
||||||
echo '<th>' . htmlspecialchars(__('Name', 'urbackup')) . '</th>';
|
|
||||||
echo '<th>' . htmlspecialchars(__('Client name', 'urbackup')) . '</th>';
|
echo '<th>' . htmlspecialchars(__('Client name', 'urbackup')) . '</th>';
|
||||||
echo '<th>' . htmlspecialchars(__('Version', 'urbackup')) . '</th>';
|
echo '<th>' . htmlspecialchars(__('Version', 'urbackup')) . '</th>';
|
||||||
echo '<th>' . htmlspecialchars(__('Status', 'urbackup')) . '</th>';
|
echo '<th>' . htmlspecialchars(__('Status', 'urbackup')) . '</th>';
|
||||||
@@ -840,8 +845,14 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
$itemUrl = $glpiItem ? $glpiItem->getLinkURL() : '';
|
$itemUrl = $glpiItem ? $glpiItem->getLinkURL() : '';
|
||||||
|
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>' . htmlspecialchars($itemTypeLabel . ' #' . $link['items_id']) . '</td>';
|
echo '<td>';
|
||||||
echo '<td>' . ($itemUrl ? '<a href="' . htmlspecialchars($itemUrl) . '">' . htmlspecialchars($clientName) . '</a>' : htmlspecialchars($clientName)) . '</td>';
|
if ($itemUrl) {
|
||||||
|
echo '<a href="' . htmlspecialchars($itemUrl) . '">' . htmlspecialchars($clientName) . '</a>';
|
||||||
|
} else {
|
||||||
|
echo htmlspecialchars($clientName);
|
||||||
|
}
|
||||||
|
echo ' <small class="text-muted">(' . htmlspecialchars($itemTypeLabel) . ')</small>';
|
||||||
|
echo '</td>';
|
||||||
echo '<td>' . htmlspecialchars($urbackupClientName) . '</td>';
|
echo '<td>' . htmlspecialchars($urbackupClientName) . '</td>';
|
||||||
echo '<td>' . htmlspecialchars($clientVersion) . '</td>';
|
echo '<td>' . htmlspecialchars($clientVersion) . '</td>';
|
||||||
echo '<td>' . $statusHtml . '</td>';
|
echo '<td>' . $statusHtml . '</td>';
|
||||||
@@ -904,6 +915,51 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$serverLocationId = (int) ($server->fields['locations_id'] ?? 0);
|
||||||
|
$linkableAssets = [];
|
||||||
|
if ($serverLocationId > 0) {
|
||||||
|
$itemtypes = Config::getEnabledItemtypes();
|
||||||
|
foreach ($unlinkedClients as $uc) {
|
||||||
|
$clientName = (string) ($uc['name'] ?? '');
|
||||||
|
if ($clientName === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$clientNameLower = strtolower($clientName);
|
||||||
|
foreach ($itemtypes as $itemtype) {
|
||||||
|
if (!class_exists($itemtype)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$assetItem = new $itemtype();
|
||||||
|
if (!$assetItem instanceof CommonDBTM) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$table = $assetItem->getTable();
|
||||||
|
if (!$DB->tableExists($table)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$assetIterator = $DB->request([
|
||||||
|
'FROM' => $table,
|
||||||
|
'WHERE' => [
|
||||||
|
'name' => $clientName,
|
||||||
|
'is_deleted' => 0,
|
||||||
|
],
|
||||||
|
'LIMIT' => 1,
|
||||||
|
]);
|
||||||
|
foreach ($assetIterator as $assetRow) {
|
||||||
|
$assetLocationId = (int) ($assetRow['locations_id'] ?? 0);
|
||||||
|
$rootLocationId = LocationHelper::getRootLocationId($assetLocationId);
|
||||||
|
if ($rootLocationId > 0 && $rootLocationId === $serverLocationId) {
|
||||||
|
$linkableAssets[$clientNameLower] = [
|
||||||
|
'itemtype' => $itemtype,
|
||||||
|
'items_id' => (int) $assetRow['id'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
echo '<table class="table table-striped table-hover">';
|
echo '<table class="table table-striped table-hover">';
|
||||||
echo '<thead>';
|
echo '<thead>';
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
@@ -912,11 +968,15 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
echo '<th>' . htmlspecialchars(__('Status', 'urbackup')) . '</th>';
|
echo '<th>' . htmlspecialchars(__('Status', 'urbackup')) . '</th>';
|
||||||
echo '<th>' . htmlspecialchars(__('Last backup', 'urbackup')) . '</th>';
|
echo '<th>' . htmlspecialchars(__('Last backup', 'urbackup')) . '</th>';
|
||||||
echo '<th>' . htmlspecialchars(__('IP address', 'urbackup')) . '</th>';
|
echo '<th>' . htmlspecialchars(__('IP address', 'urbackup')) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(__('Actions', 'urbackup')) . '</th>';
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
echo '</thead>';
|
echo '</thead>';
|
||||||
echo '<tbody>';
|
echo '<tbody>';
|
||||||
|
|
||||||
foreach ($unlinkedClients as $uc) {
|
foreach ($unlinkedClients as $uc) {
|
||||||
|
$clientName = (string) ($uc['name'] ?? 'Unknown');
|
||||||
|
$clientNameLower = strtolower($clientName);
|
||||||
|
|
||||||
$online = $uc['online'] ?? null;
|
$online = $uc['online'] ?? null;
|
||||||
$apiStatusString = $uc['status'] ?? '';
|
$apiStatusString = $uc['status'] ?? '';
|
||||||
$statusHtml = self::renderOnlineBadge($online, $apiStatusString);
|
$statusHtml = self::renderOnlineBadge($online, $apiStatusString);
|
||||||
@@ -928,15 +988,280 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
$clientVersion = $uc['client_version_string'] ?? $uc['client_version'] ?? '-';
|
$clientVersion = $uc['client_version_string'] ?? $uc['client_version'] ?? '-';
|
||||||
|
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>' . htmlspecialchars((string) ($uc['name'] ?? 'Unknown')) . '</td>';
|
echo '<td>' . htmlspecialchars($clientName) . '</td>';
|
||||||
echo '<td>' . htmlspecialchars($clientVersion) . '</td>';
|
echo '<td>' . htmlspecialchars($clientVersion) . '</td>';
|
||||||
echo '<td>' . $statusHtml . '</td>';
|
echo '<td>' . $statusHtml . '</td>';
|
||||||
echo '<td>' . htmlspecialchars($lastBackup ?: '-') . '</td>';
|
echo '<td>' . htmlspecialchars($lastBackup ?: '-') . '</td>';
|
||||||
echo '<td>' . htmlspecialchars($clientIp ?: '-') . '</td>';
|
echo '<td>' . htmlspecialchars($clientIp ?: '-') . '</td>';
|
||||||
|
echo '<td>';
|
||||||
|
if (isset($linkableAssets[$clientNameLower])) {
|
||||||
|
$match = $linkableAssets[$clientNameLower];
|
||||||
|
$formAction = PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php';
|
||||||
|
echo '<form method="post" action="' . htmlspecialchars($formAction) . '" class="d-inline">';
|
||||||
|
echo Html::hidden('_glpi_csrf_token', ['value' => Session::getNewCSRFToken()]);
|
||||||
|
echo Html::hidden('itemtype', ['value' => $match['itemtype']]);
|
||||||
|
echo Html::hidden('items_id', ['value' => $match['items_id']]);
|
||||||
|
echo Html::hidden('id', ['value' => (int) $server->fields['id']]);
|
||||||
|
echo '<button type="submit" name="link_asset" value="1" class="btn btn-primary btn-sm">';
|
||||||
|
echo htmlspecialchars(__('Connect'));
|
||||||
|
echo '</button>';
|
||||||
|
Html::closeForm();
|
||||||
|
} else {
|
||||||
|
echo '<span class="text-muted">—</span>';
|
||||||
|
}
|
||||||
|
echo '</td>';
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '</tbody>';
|
echo '</tbody>';
|
||||||
echo '</table>';
|
echo '</table>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function showMissingClientsTab(Server $server): void
|
||||||
|
{
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
$apiStatus = (int) ($server->fields['last_api_status'] ?? 0);
|
||||||
|
if ($apiStatus !== 1) {
|
||||||
|
echo '<div class="alert alert-warning">';
|
||||||
|
echo htmlspecialchars(__('API connection not working. Save server to test connection.', 'urbackup'));
|
||||||
|
echo '</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$serverLocationId = (int) ($server->fields['locations_id'] ?? 0);
|
||||||
|
if ($serverLocationId <= 0) {
|
||||||
|
echo '<div class="alert alert-info">';
|
||||||
|
echo htmlspecialchars(__('No location configured for this server.', 'urbackup'));
|
||||||
|
echo '</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rootLocationId = LocationHelper::getRootLocationId($serverLocationId);
|
||||||
|
|
||||||
|
$linkedIterator = $DB->request([
|
||||||
|
'FROM' => ServerAsset::getTable(),
|
||||||
|
]);
|
||||||
|
$linkedAssetKeys = [];
|
||||||
|
foreach ($linkedIterator as $row) {
|
||||||
|
$linkedAssetKeys[$row['itemtype'] . ':' . $row['items_id']] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$client = new UrbackupApiClient($server);
|
||||||
|
$urbackupClients = $client->getStatus();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo '<div class="alert alert-danger">';
|
||||||
|
echo htmlspecialchars($e->getMessage());
|
||||||
|
echo '</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$urbackupClientNames = [];
|
||||||
|
foreach ($urbackupClients as $uc) {
|
||||||
|
$name = strtolower((string) ($uc['name'] ?? $uc['clientname'] ?? $uc['hostname'] ?? ''));
|
||||||
|
if ($name !== '') {
|
||||||
|
$urbackupClientNames[$name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$cacheEntity = [];
|
||||||
|
$cacheLocation = [];
|
||||||
|
$cacheState = [];
|
||||||
|
$cacheUser = [];
|
||||||
|
$cacheGroup = [];
|
||||||
|
|
||||||
|
$itemtypes = Config::getEnabledItemtypes();
|
||||||
|
$missingAssets = [];
|
||||||
|
|
||||||
|
foreach ($itemtypes as $itemtype) {
|
||||||
|
if (!class_exists($itemtype)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$assetItem = new $itemtype();
|
||||||
|
if (!$assetItem instanceof CommonDBTM) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$table = $assetItem->getTable();
|
||||||
|
if (!$DB->tableExists($table)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator = $DB->request([
|
||||||
|
'FROM' => $table,
|
||||||
|
'WHERE' => [
|
||||||
|
'is_deleted' => 0,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($iterator as $assetRow) {
|
||||||
|
$name = (string) ($assetRow['name'] ?? '');
|
||||||
|
if ($name === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$nameLower = strtolower($name);
|
||||||
|
|
||||||
|
$assetLocationId = (int) ($assetRow['locations_id'] ?? 0);
|
||||||
|
$assetRootLocationId = LocationHelper::getRootLocationId($assetLocationId);
|
||||||
|
|
||||||
|
if ($assetRootLocationId !== $rootLocationId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $itemtype . ':' . $assetRow['id'];
|
||||||
|
$assetId = (int) $assetRow['id'];
|
||||||
|
|
||||||
|
if (isset($linkedAssetKeys[$key])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isset($urbackupClientNames[$nameLower])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entityName = self::getCachedName('Entity', (int) ($assetRow['entities_id'] ?? 0), $cacheEntity);
|
||||||
|
$locationName = self::getCachedLocationName($assetLocationId, $cacheLocation);
|
||||||
|
$stateName = self::getCachedName('State', (int) ($assetRow['states_id'] ?? 0), $cacheState);
|
||||||
|
$userName = self::getCachedName('User', (int) ($assetRow['users_id'] ?? 0), $cacheUser);
|
||||||
|
$groupName = self::getCachedName('Group', (int) ($assetRow['groups_id'] ?? 0), $cacheGroup);
|
||||||
|
|
||||||
|
$ip = self::getAssetIp($itemtype, $assetId);
|
||||||
|
|
||||||
|
$missingAssets[] = [
|
||||||
|
'itemtype' => $itemtype,
|
||||||
|
'items_id' => $assetId,
|
||||||
|
'name' => $name,
|
||||||
|
'entity' => $entityName,
|
||||||
|
'location' => $locationName,
|
||||||
|
'otherserial' => (string) ($assetRow['otherserial'] ?? ''),
|
||||||
|
'ip' => $ip,
|
||||||
|
'state' => $stateName,
|
||||||
|
'user' => $userName,
|
||||||
|
'group' => $groupName,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($missingAssets) === 0) {
|
||||||
|
echo '<div class="alert alert-success">';
|
||||||
|
echo htmlspecialchars(__('All assets in this location are linked or already on the UrBackup server.', 'urbackup'));
|
||||||
|
echo '</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$formAction = PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php';
|
||||||
|
|
||||||
|
echo '<table class="table table-striped table-hover">';
|
||||||
|
echo '<thead><tr>';
|
||||||
|
echo '<th>' . htmlspecialchars(__('Name')) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(Entity::getTypeName(1)) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(Location::getTypeName(1)) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(__('Inventory number')) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(__('IP address', 'urbackup')) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(State::getTypeName(1)) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(User::getTypeName(1)) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(Group::getTypeName(1)) . '</th>';
|
||||||
|
echo '<th>' . htmlspecialchars(__('Actions', 'urbackup')) . '</th>';
|
||||||
|
echo '</tr></thead>';
|
||||||
|
echo '<tbody>';
|
||||||
|
|
||||||
|
foreach ($missingAssets as $asset) {
|
||||||
|
echo '<tr>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['name']) . '</td>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['entity']) . '</td>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['location']) . '</td>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['otherserial']) . '</td>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['ip']) . '</td>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['state']) . '</td>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['user']) . '</td>';
|
||||||
|
echo '<td>' . htmlspecialchars($asset['group']) . '</td>';
|
||||||
|
echo '<td>';
|
||||||
|
echo '<form method="post" action="' . htmlspecialchars($formAction) . '" class="d-inline">';
|
||||||
|
echo Html::hidden('_glpi_csrf_token', ['value' => Session::getNewCSRFToken()]);
|
||||||
|
echo Html::hidden('itemtype', ['value' => $asset['itemtype']]);
|
||||||
|
echo Html::hidden('items_id', ['value' => $asset['items_id']]);
|
||||||
|
echo Html::hidden('id', ['value' => (int) $server->fields['id']]);
|
||||||
|
echo '<button type="submit" name="link_asset" value="1" class="btn btn-primary btn-sm">';
|
||||||
|
echo htmlspecialchars(__('Connect'));
|
||||||
|
echo '</button>';
|
||||||
|
Html::closeForm();
|
||||||
|
echo '</td>';
|
||||||
|
echo '</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '</tbody>';
|
||||||
|
echo '</table>';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getCachedName(string $classname, int $id, array &$cache): string
|
||||||
|
{
|
||||||
|
if ($id <= 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (!isset($cache[$id])) {
|
||||||
|
$fqcn = '\\' . ltrim($classname, '\\');
|
||||||
|
$obj = new $fqcn();
|
||||||
|
if ($obj->getFromDB($id)) {
|
||||||
|
$cache[$id] = (string) ($obj->fields['name'] ?? '');
|
||||||
|
} else {
|
||||||
|
$cache[$id] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $cache[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getCachedLocationName(int $id, array &$cache): string
|
||||||
|
{
|
||||||
|
if ($id <= 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (!isset($cache[$id])) {
|
||||||
|
$obj = new Location();
|
||||||
|
if ($obj->getFromDB($id)) {
|
||||||
|
$cache[$id] = (string) ($obj->fields['completename'] ?? $obj->fields['name'] ?? '');
|
||||||
|
} else {
|
||||||
|
$cache[$id] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $cache[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getAssetIp(string $itemtype, int $items_id): string
|
||||||
|
{
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
$iterator = $DB->request([
|
||||||
|
'SELECT' => ['ipa.name'],
|
||||||
|
'FROM' => 'glpi_ipaddresses AS ipa',
|
||||||
|
'INNER JOIN' => [
|
||||||
|
'glpi_networknames AS nn' => [
|
||||||
|
'ON' => [
|
||||||
|
'nn' => 'items_id',
|
||||||
|
'ipa' => 'id',
|
||||||
|
['AND' => ['ipa.itemtype' => 'NetworkName']],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'glpi_networkports AS np' => [
|
||||||
|
'ON' => [
|
||||||
|
'np' => 'id',
|
||||||
|
'nn' => 'items_id',
|
||||||
|
['AND' => ['nn.itemtype' => 'NetworkPort']],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'WHERE' => [
|
||||||
|
'np.itemtype' => $itemtype,
|
||||||
|
'np.items_id' => $items_id,
|
||||||
|
],
|
||||||
|
'LIMIT' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($iterator as $row) {
|
||||||
|
$ip = (string) ($row['name'] ?? '');
|
||||||
|
if ($ip !== '') {
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ class UrbackupApiClient
|
|||||||
|
|
||||||
private string $server_version = '';
|
private string $server_version = '';
|
||||||
|
|
||||||
private bool $is_version_2_5_or_higher = false;
|
private bool $is_version_2_4_or_higher = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -52,15 +52,10 @@ class UrbackupApiClient
|
|||||||
$this->password = (string) ($server->fields['api_password'] ?? '');
|
$this->password = (string) ($server->fields['api_password'] ?? '');
|
||||||
$this->ignore_ssl = ((int) ($server->fields['ignore_ssl'] ?? 0)) === 1;
|
$this->ignore_ssl = ((int) ($server->fields['ignore_ssl'] ?? 0)) === 1;
|
||||||
$this->server_version = (string) ($server->fields['server_version'] ?? '');
|
$this->server_version = (string) ($server->fields['server_version'] ?? '');
|
||||||
$this->is_version_2_5_or_higher = $this->detectVersion2_5OrHigher();
|
$this->is_version_2_4_or_higher = $this->detectVersion2_4OrHigher();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function detectVersion2_4OrHigher(): bool
|
||||||
* Detect if server version is 2.5 or higher.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function detectVersion2_5OrHigher(): bool
|
|
||||||
{
|
{
|
||||||
if ($this->server_version === '') {
|
if ($this->server_version === '') {
|
||||||
return false;
|
return false;
|
||||||
@@ -77,7 +72,7 @@ class UrbackupApiClient
|
|||||||
if ($major > 2) {
|
if ($major > 2) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($major === 2 && $minor >= 5) {
|
if ($major === 2 && $minor >= 4) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +86,7 @@ class UrbackupApiClient
|
|||||||
*/
|
*/
|
||||||
public function getInternetModeSettingKey(): string
|
public function getInternetModeSettingKey(): string
|
||||||
{
|
{
|
||||||
return $this->is_version_2_5_or_higher ? 'internet_mode_enabled' : 'internet_mode';
|
return $this->is_version_2_4_or_higher ? 'internet_mode_enabled' : 'internet_mode';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -391,7 +386,7 @@ class UrbackupApiClient
|
|||||||
'sa' => 'clientsettings_save',
|
'sa' => 'clientsettings_save',
|
||||||
't_clientid' => $client_id,
|
't_clientid' => $client_id,
|
||||||
'overwrite' => 'true',
|
'overwrite' => 'true',
|
||||||
$key => $enabled ? '1' : '0',
|
$key => $enabled ? 'true' : 'false',
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = $this->apiAction('settings', $params);
|
$data = $this->apiAction('settings', $params);
|
||||||
|
|||||||
@@ -7,14 +7,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">{{ __('UrBackup server selection', 'urbackup') }}</th>
|
<th colspan="2">{{ __('UrBackup server selection', 'urbackup') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="tab_bg_1">
|
|
||||||
<td>{{ __('Asset location ID', 'urbackup') }}</td>
|
|
||||||
<td>{{ asset_location_id }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="tab_bg_1">
|
|
||||||
<td>{{ __('Root location ID', 'urbackup') }}</td>
|
|
||||||
<td>{{ root_location_id }}</td>
|
|
||||||
</tr>
|
|
||||||
{% if is_sub_location %}
|
{% if is_sub_location %}
|
||||||
<tr class="tab_bg_1">
|
<tr class="tab_bg_1">
|
||||||
<td colspan="2"><em>
|
<td colspan="2"><em>
|
||||||
|
|||||||
Reference in New Issue
Block a user