Compare commits
16 Commits
6a49489b73
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| f7c1ab8aa4 | |||
| f0a5be45ee | |||
| f0eaa76f17 | |||
| 223180d1a9 | |||
| 5fac26040a | |||
| 9ee28330ac | |||
| 8a52489b41 | |||
| 9979d62a2a | |||
| 01d678e855 | |||
| 0e80c1430f | |||
| d69c465c92 | |||
| aba2ecf4aa | |||
| df28fc0018 | |||
| 7a578db677 | |||
| 771409e396 | |||
| 6441a8636d |
@@ -267,3 +267,56 @@ Il test del pulsante "Test API" continua a restituire 403 Forbidden quando acces
|
|||||||
- `src/AssetTab.php`: Aggiunti metodi `startBackup()`, `saveInternetMode()`, `saveDefaultDirs()`
|
- `src/AssetTab.php`: Aggiunti metodi `startBackup()`, `saveInternetMode()`, `saveDefaultDirs()`
|
||||||
- `src/UrbackupApiClient.php`: Aggiunti metodi `updateClientSettings()`, `saveInternetMode()`
|
- `src/UrbackupApiClient.php`: Aggiunti metodi `updateClientSettings()`, `saveInternetMode()`
|
||||||
- `front/asset.form.php`: Gestione azioni per salvataggio impostazioni e backup
|
- `front/asset.form.php`: Gestione azioni per salvataggio impostazioni e backup
|
||||||
|
|
||||||
|
### Refactoring server.form.php e nuove tab (v0.4.7)
|
||||||
|
|
||||||
|
**Data**: 2026-05-21
|
||||||
|
|
||||||
|
**Descrizione**: Restrutturazione completa della pagina server con tab laterali e nuove funzionalità:
|
||||||
|
|
||||||
|
**Refactoring Server::showForm()**:
|
||||||
|
- Estratto `showFormFields(?int $ID)` da `showForm()` per permettere layout custom
|
||||||
|
- `showForm()` ora chiama header + fields + buttons in sequenza
|
||||||
|
|
||||||
|
**Tab laterali (server.form.php)**:
|
||||||
|
- Side tabs a sinistra (col-2) con `nav-pills flex-column`
|
||||||
|
- 4 tab: Server, Linked clients, Unlinked clients, Missing clients
|
||||||
|
- Tab persistence via URL hash (JS su `shown.bs.tab`)
|
||||||
|
|
||||||
|
**Missing clients tab**:
|
||||||
|
- Mostra asset GLPI con root location matching, non ancora collegati a ServerAsset e non presenti su UrBackup
|
||||||
|
- Colonne: Name (link all'asset), Entity, Location (completename), Inventory number, IP, State, User, Group
|
||||||
|
- Ricerca testuale client-side
|
||||||
|
- Ordinamento colonne click-to-sort vanilla JS
|
||||||
|
- Navigazione server spostata in server.form.php (sopra i tab, indipendente dalle sezioni)
|
||||||
|
|
||||||
|
**Bug fix namespace risolto**:
|
||||||
|
- `getCachedName()` usava `new $classname()` con stringa → PHP cercava `GlpiPlugin\Urbackup\Group` invece di `\Group`
|
||||||
|
- Fix: `$fqcn = '\\' . ltrim($classname, '\\')` per forzare global namespace
|
||||||
|
|
||||||
|
**Gruppo asset corretto**:
|
||||||
|
- Gruppo non in `glpi_computers.groups_id` (colonna inesistente)
|
||||||
|
- Letto da `glpi_groups_items` WHERE `type = 1` (GROUP_TYPE_NORMAL)
|
||||||
|
- Usa `completename` per gerarchia (es. "Helpdesk > Livello 1")
|
||||||
|
|
||||||
|
**Indirizzo IP asset**:
|
||||||
|
- Query JOIN: `glpi_ipaddresses → glpi_networknames → glpi_networkports`
|
||||||
|
- Primo IP valido per l'item
|
||||||
|
|
||||||
|
**Breadcrumb**:
|
||||||
|
- Cambiato da `'Assets'` a `'admin'` in `Html::header()` di server.php e server.form.php
|
||||||
|
- Mostra: Pagina principale > Amministrazione > UrBackup servers
|
||||||
|
|
||||||
|
**Fix port default per nuovi server**:
|
||||||
|
- `prepareInputForAdd()` ora setta default 55414 per `port`, 'http' per `protocol`, 1 per `is_active`, ecc.
|
||||||
|
- `prepareInputForUpdate()` normalizza anche valori vuoti
|
||||||
|
|
||||||
|
**File modificati**:
|
||||||
|
- `src/Server.php`: `showFormFields()`, `showMissingClientsTab()`, `getCachedName()` fix, `getAssetGroupName()`, `getAssetIp()`, `getCachedLocationName()`, `prepareInputForAdd/Update` default fix, icona `ti-cloud-up`
|
||||||
|
- `front/server.form.php`: Tab laterali, tab hash JS, breadcrumb admin, navigazione server
|
||||||
|
- `front/server.php`: Breadcrumb admin, rimosso pulsante "Add" manuale
|
||||||
|
- `src/Profile.php`: Icona `ti-cloud-up`
|
||||||
|
- `src/AssetTab.php`: Icona `ti-cloud-up`
|
||||||
|
- **Permessi**: `front/server.form.php` ora usa READ invece di UPDATE per accesso form; View search option + pulsanti Connect nascosti per READ; API username/password nascosti per READ
|
||||||
|
- **i18n**: aggiunte 17 stringhe mancanti con dominio `urbackup` a tutti i file e .po/.mo (it, en, de)
|
||||||
|
- **Bug fix**: ServerAsset colonne rimosse, asset.form.php usa disconnectAsset(), `declare(strict_types=1)` in 11 file
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "finstral/glpi-urbackup-plugin",
|
||||||
|
"description": "UrBackup integration plugin for GLPI 11",
|
||||||
|
"type": "glpi-plugin",
|
||||||
|
"license": "GPL-2.0-or-later",
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.3"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"GlpiPlugin\\Urbackup\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"sort-packages": true
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"glpi-plugin": {
|
||||||
|
"key": "urbackup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "finstral/glpi-urbackup-plugin",
|
"name": "glpi/urbackup-plugin",
|
||||||
"description": "UrBackup integration plugin for GLPI 11",
|
"description": "UrBackup integration plugin for GLPI 11",
|
||||||
"type": "glpi-plugin",
|
"type": "glpi-plugin",
|
||||||
"license": "GPL-2.0-or-later",
|
"license": "GPL-2.0-or-later",
|
||||||
|
|||||||
+9
-15
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
* UrBackup plugin for GLPI
|
* UrBackup plugin for GLPI
|
||||||
@@ -25,11 +27,11 @@ $itemtype = (string) ($_POST['itemtype'] ?? $_GET['itemtype'] ?? '');
|
|||||||
$items_id = (int) ($_POST['items_id'] ?? $_GET['items_id'] ?? 0);
|
$items_id = (int) ($_POST['items_id'] ?? $_GET['items_id'] ?? 0);
|
||||||
|
|
||||||
if ($itemtype === '' || $items_id <= 0) {
|
if ($itemtype === '' || $items_id <= 0) {
|
||||||
Html::displayValidationError(__('Invalid parameters'));
|
Html::displayValidationError(__('Invalid parameters', 'urbackup'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_array($itemtype, Config::getEnabledItemtypes(), true)) {
|
if (!in_array($itemtype, Config::getEnabledItemtypes(), true)) {
|
||||||
Html::displayValidationError(__('Item type not enabled for UrBackup'));
|
Html::displayValidationError(__('Item type not enabled for UrBackup', 'urbackup'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$item = getItemForItemtype($itemtype);
|
$item = getItemForItemtype($itemtype);
|
||||||
@@ -46,13 +48,13 @@ if (isset($_POST['connect'])) {
|
|||||||
$server_id = (int) ($_POST['plugin_urbackup_servers_id'] ?? 0);
|
$server_id = (int) ($_POST['plugin_urbackup_servers_id'] ?? 0);
|
||||||
|
|
||||||
if ($server_id <= 0) {
|
if ($server_id <= 0) {
|
||||||
Html::displayValidationError(__('No server selected'));
|
Html::displayValidationError(__('No server selected', 'urbackup'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$link = ServerAsset::getLinkForAsset($itemtype, $items_id);
|
$link = ServerAsset::getLinkForAsset($itemtype, $items_id);
|
||||||
|
|
||||||
if ($link !== null) {
|
if ($link !== null) {
|
||||||
Html::displayValidationError(__('Asset is already linked to a server'));
|
Html::displayValidationError(__('Asset is already linked to a server', 'urbackup'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = ServerAsset::createForAsset($itemtype, $items_id, $server_id);
|
$result = ServerAsset::createForAsset($itemtype, $items_id, $server_id);
|
||||||
@@ -61,7 +63,7 @@ if (isset($_POST['connect'])) {
|
|||||||
$item->getFromDB($items_id);
|
$item->getFromDB($items_id);
|
||||||
Html::redirect($item->getLinkURL());
|
Html::redirect($item->getLinkURL());
|
||||||
} else {
|
} else {
|
||||||
Html::displayValidationError(__('Failed to link asset to server'));
|
Html::displayValidationError(__('Failed to link asset to server', 'urbackup'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,21 +72,13 @@ if (isset($_POST['disconnect'])) {
|
|||||||
Html::displayRightError();
|
Html::displayRightError();
|
||||||
}
|
}
|
||||||
|
|
||||||
global $DB;
|
$result = ServerAsset::disconnectAsset($itemtype, $items_id);
|
||||||
|
|
||||||
$link = ServerAsset::getLinkForAsset($itemtype, $items_id, false);
|
|
||||||
|
|
||||||
if ($link === null) {
|
|
||||||
Html::displayValidationError(__('Asset is not linked to any server'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $DB->delete('glpi_plugin_urbackup_serverassets', ['id' => (int) $link['id']]);
|
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$item->getFromDB($items_id);
|
$item->getFromDB($items_id);
|
||||||
Html::redirect($item->getLinkURL());
|
Html::redirect($item->getLinkURL());
|
||||||
} else {
|
} else {
|
||||||
Html::displayValidationError(__('Failed to disconnect asset from server'));
|
Html::displayValidationError(__('Failed to disconnect asset from server', 'urbackup'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use GlpiPlugin\Urbackup\Config;
|
use GlpiPlugin\Urbackup\Config;
|
||||||
use Html;
|
use Html;
|
||||||
|
|
||||||
|
|||||||
+112
-25
@@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use GlpiPlugin\Urbackup\Profile;
|
use GlpiPlugin\Urbackup\Profile;
|
||||||
use GlpiPlugin\Urbackup\Server;
|
use GlpiPlugin\Urbackup\Server;
|
||||||
use GlpiPlugin\Urbackup\ServerAsset;
|
use GlpiPlugin\Urbackup\ServerAsset;
|
||||||
use Html;
|
|
||||||
|
|
||||||
if (!defined('GLPI_ROOT')) {
|
if (!defined('GLPI_ROOT')) {
|
||||||
define('GLPI_ROOT', dirname(__DIR__, 4));
|
define('GLPI_ROOT', dirname(__DIR__, 4));
|
||||||
@@ -11,7 +12,7 @@ if (!defined('GLPI_ROOT')) {
|
|||||||
|
|
||||||
include_once GLPI_ROOT . "/inc/includes.php";
|
include_once GLPI_ROOT . "/inc/includes.php";
|
||||||
|
|
||||||
if (!Profile::canCurrentUser(UPDATE)) {
|
if (!Profile::canCurrentUser(READ)) {
|
||||||
Html::displayRightError();
|
Html::displayRightError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,11 +28,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
ServerAsset::connectAssetToServer($itemtype, $items_id, $server_id);
|
ServerAsset::connectAssetToServer($itemtype, $items_id, $server_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
Html::redirect(PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php?id=' . $server_id);
|
Html::redirect(PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php?id=' . $server_id);
|
||||||
=======
|
|
||||||
Html::redirect(PLUGIN_URBACKUP_WEB_DIR . '/front/server.php?id=' . $server_id);
|
|
||||||
>>>>>>> collegamento_e_verifica_host
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$id = $_POST['id'] ?? 0;
|
$id = $_POST['id'] ?? 0;
|
||||||
@@ -52,30 +49,120 @@ $ID = $_GET['id'] ?? null;
|
|||||||
Html::header(
|
Html::header(
|
||||||
$ID ? __('Edit UrBackup server', 'urbackup') : __('Add UrBackup server', 'urbackup'),
|
$ID ? __('Edit UrBackup server', 'urbackup') : __('Add UrBackup server', 'urbackup'),
|
||||||
'',
|
'',
|
||||||
'Assets',
|
'admin',
|
||||||
'GlpiPlugin\Urbackup\Server'
|
'GlpiPlugin\Urbackup\Server'
|
||||||
);
|
);
|
||||||
|
|
||||||
$server->showForm($ID);
|
if ($ID > 0) {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
if ($ID > 0 && $server->getFromDB($ID)) {
|
$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">';
|
$serverIterator = $DB->request([
|
||||||
echo '<div class="card-header">';
|
'FROM' => Server::getTable(),
|
||||||
echo '<h5 class="mb-0">' . htmlspecialchars(__('Unlinked clients', 'urbackup')) . '</h5>';
|
'ORDER' => 'name',
|
||||||
echo '</div>';
|
]);
|
||||||
echo '<div class="card-body">';
|
$serverIds = [];
|
||||||
Server::showUnlinkedClientsTab($server);
|
foreach ($serverIterator as $row) {
|
||||||
echo '</div>';
|
$serverIds[(int) $row['id']] = (string) $row['name'];
|
||||||
echo '</div>';
|
}
|
||||||
|
$serverIdKeys = array_keys($serverIds);
|
||||||
|
$currentIndex = array_search((int) $ID, $serverIdKeys, true);
|
||||||
|
$totalServers = count($serverIds);
|
||||||
|
$prevId = ($currentIndex !== false && $currentIndex > 0) ? $serverIdKeys[$currentIndex - 1] : null;
|
||||||
|
$nextId = ($currentIndex !== false && $currentIndex < $totalServers - 1) ? $serverIdKeys[$currentIndex + 1] : null;
|
||||||
|
|
||||||
|
$baseUrl = PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php';
|
||||||
|
?>
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<a href="<?php echo htmlspecialchars(PLUGIN_URBACKUP_WEB_DIR . '/front/server.php'); ?>" class="btn btn-sm btn-icon btn-ghost-secondary me-2"
|
||||||
|
data-bs-toggle="tooltip" data-bs-placement="bottom" title="<?php echo htmlspecialchars(__('List')); ?>">
|
||||||
|
<i class="ti ti-list-search fs-2"></i>
|
||||||
|
</a>
|
||||||
|
<?php if ($prevId !== null): ?>
|
||||||
|
<a href="<?php echo htmlspecialchars($baseUrl . '?id=' . $prevId); ?>"
|
||||||
|
class="btn btn-sm btn-icon btn-ghost-secondary me-2"
|
||||||
|
data-bs-toggle="tooltip" data-bs-placement="bottom" title="<?php echo htmlspecialchars(__('Previous')); ?>">
|
||||||
|
<i class="fs-2 ti ti-chevron-left"></i>
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="btn btn-sm btn-icon btn-ghost-secondary me-2 bs-invisible">
|
||||||
|
<i class="fs-2 ti ti-chevron-left"></i>
|
||||||
|
</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<span class="fw-bold mx-2"><?php echo htmlspecialchars(($currentIndex !== false ? $currentIndex + 1 : 1) . ' / ' . $totalServers); ?></span>
|
||||||
|
<?php if ($nextId !== null): ?>
|
||||||
|
<a href="<?php echo htmlspecialchars($baseUrl . '?id=' . $nextId); ?>"
|
||||||
|
class="btn btn-sm btn-icon btn-ghost-secondary ms-2"
|
||||||
|
data-bs-toggle="tooltip" data-bs-placement="bottom" title="<?php echo htmlspecialchars(__('Next')); ?>">
|
||||||
|
<i class="fs-2 ti ti-chevron-right"></i>
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="btn btn-sm btn-icon btn-ghost-secondary ms-2 bs-invisible">
|
||||||
|
<i class="fs-2 ti ti-chevron-right"></i>
|
||||||
|
</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var hash = window.location.hash;
|
||||||
|
if (hash) {
|
||||||
|
$('[data-bs-toggle="tab"][href="' + hash + '"]').tab('show');
|
||||||
|
}
|
||||||
|
$('[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||||
|
window.location.hash = $(this).attr('href');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
Html::footer();
|
Html::footer();
|
||||||
+5
-17
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use GlpiPlugin\Urbackup\Profile;
|
use GlpiPlugin\Urbackup\Profile;
|
||||||
use GlpiPlugin\Urbackup\Server;
|
use GlpiPlugin\Urbackup\Server;
|
||||||
use Html;
|
use Html;
|
||||||
@@ -15,27 +17,13 @@ if (!Profile::canCurrentUser(READ)) {
|
|||||||
Html::displayRightError();
|
Html::displayRightError();
|
||||||
}
|
}
|
||||||
|
|
||||||
$can_read = Profile::canCurrentUser(READ);
|
|
||||||
$can_create = Profile::canCurrentUser(CREATE);
|
|
||||||
|
|
||||||
Html::header(
|
Html::header(
|
||||||
'UrBackup Servers',
|
__('UrBackup Servers', 'urbackup'),
|
||||||
'',
|
'',
|
||||||
'Assets',
|
'admin',
|
||||||
''
|
'GlpiPlugin\Urbackup\Server'
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($can_create) {
|
|
||||||
echo "<div class='center'>";
|
|
||||||
echo Html::link(
|
|
||||||
__('Add UrBackup server', 'urbackup'),
|
|
||||||
'/plugins/urbackup/front/server.form.php',
|
|
||||||
['class' => 'btn btn-primary']
|
|
||||||
);
|
|
||||||
echo "</div>";
|
|
||||||
echo "<br>";
|
|
||||||
}
|
|
||||||
|
|
||||||
Search::show('GlpiPlugin\Urbackup\Server', [
|
Search::show('GlpiPlugin\Urbackup\Server', [
|
||||||
'is_deleted' => 0,
|
'is_deleted' => 0,
|
||||||
'massiveaction' => true,
|
'massiveaction' => true,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AJAX endpoint for testing UrBackup API
|
* AJAX endpoint for testing UrBackup API
|
||||||
*/
|
*/
|
||||||
@@ -11,21 +14,21 @@ Html::header_nocache();
|
|||||||
Session::checkLoginUser();
|
Session::checkLoginUser();
|
||||||
|
|
||||||
if (!Session::haveRight('plugin_urbackup', READ)) {
|
if (!Session::haveRight('plugin_urbackup', READ)) {
|
||||||
echo json_encode(['success' => false, 'message' => 'No permission']);
|
echo json_encode(['success' => false, 'message' => __('No permission', 'urbackup')]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$server_id = (int) ($_POST['id'] ?? $_GET['id'] ?? 0);
|
$server_id = (int) ($_POST['id'] ?? $_GET['id'] ?? 0);
|
||||||
|
|
||||||
if ($server_id <= 0) {
|
if ($server_id <= 0) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Invalid server ID']);
|
echo json_encode(['success' => false, 'message' => __('Invalid server ID', 'urbackup')]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$server = new GlpiPlugin\Urbackup\Server();
|
$server = new GlpiPlugin\Urbackup\Server();
|
||||||
|
|
||||||
if (!$server->getFromDB($server_id)) {
|
if (!$server->getFromDB($server_id)) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Server not found']);
|
echo json_encode(['success' => false, 'message' => __('Server not found', 'urbackup')]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-11
@@ -1,26 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
* UrBackup plugin for GLPI
|
* UrBackup plugin for GLPI
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
*
|
|
||||||
* Install/update process for GLPI 11.
|
|
||||||
*
|
|
||||||
* GLPI 11 Migration class does not expose createTable()/addTable().
|
|
||||||
* Compatible GLPI plugin pattern:
|
|
||||||
*
|
|
||||||
* - initial schema creation from SQL file using $DB->runFile()
|
|
||||||
* - schema evolution using Migration addField(), addKey(), executeMigration()
|
|
||||||
*
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use GlpiPlugin\Urbackup\Config;
|
use GlpiPlugin\Urbackup\Config;
|
||||||
use GlpiPlugin\Urbackup\Profile;
|
use GlpiPlugin\Urbackup\Profile;
|
||||||
|
|
||||||
if (!defined('GLPI_ROOT')) {
|
if (!defined('GLPI_ROOT')) {
|
||||||
die('Sorry. You cannot access this file directly.');
|
die(__('Sorry. You cannot access this file directly.', 'urbackup'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
* UrBackup plugin for GLPI
|
* UrBackup plugin for GLPI
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
*
|
|
||||||
* Uninstall process for GLPI 11.
|
|
||||||
* -------------------------------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use GlpiPlugin\Urbackup\Profile;
|
use GlpiPlugin\Urbackup\Profile;
|
||||||
|
|
||||||
if (!defined('GLPI_ROOT')) {
|
if (!defined('GLPI_ROOT')) {
|
||||||
die('Sorry. You cannot access this file directly.');
|
die(__('Sorry. You cannot access this file directly.', 'urbackup'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Binary file not shown.
@@ -156,3 +156,54 @@ msgstr "Letztes Backup"
|
|||||||
|
|
||||||
msgid "Show"
|
msgid "Show"
|
||||||
msgstr "Anzeigen"
|
msgstr "Anzeigen"
|
||||||
|
|
||||||
|
msgid "HTTP"
|
||||||
|
msgstr "HTTP"
|
||||||
|
|
||||||
|
msgid "HTTPS"
|
||||||
|
msgstr "HTTPS"
|
||||||
|
|
||||||
|
msgid "API Error"
|
||||||
|
msgstr "API-Fehler"
|
||||||
|
|
||||||
|
msgid "Unknown"
|
||||||
|
msgstr "Unbekannt"
|
||||||
|
|
||||||
|
msgid "Asset Definition"
|
||||||
|
msgstr "Asset-Definition"
|
||||||
|
|
||||||
|
msgid "Legacy"
|
||||||
|
msgstr "Legacy"
|
||||||
|
|
||||||
|
msgid "UrBackup Servers"
|
||||||
|
msgstr "UrBackup-Server"
|
||||||
|
|
||||||
|
msgid "Invalid parameters"
|
||||||
|
msgstr "Ungültige Parameter"
|
||||||
|
|
||||||
|
msgid "Item type not enabled for UrBackup"
|
||||||
|
msgstr "Elementtyp für UrBackup nicht aktiviert"
|
||||||
|
|
||||||
|
msgid "No server selected"
|
||||||
|
msgstr "Kein Server ausgewählt"
|
||||||
|
|
||||||
|
msgid "Asset is already linked to a server"
|
||||||
|
msgstr "Asset ist bereits mit einem Server verknüpft"
|
||||||
|
|
||||||
|
msgid "Failed to link asset to server"
|
||||||
|
msgstr "Verknüpfung von Asset mit Server fehlgeschlagen"
|
||||||
|
|
||||||
|
msgid "Failed to disconnect asset from server"
|
||||||
|
msgstr "Trennung von Asset vom Server fehlgeschlagen"
|
||||||
|
|
||||||
|
msgid "No permission"
|
||||||
|
msgstr "Keine Berechtigung"
|
||||||
|
|
||||||
|
msgid "Invalid server ID"
|
||||||
|
msgstr "Ungültige Server-ID"
|
||||||
|
|
||||||
|
msgid "Server not found"
|
||||||
|
msgstr "Server nicht gefunden"
|
||||||
|
|
||||||
|
msgid "Sorry. You cannot access this file directly."
|
||||||
|
msgstr "Entschuldigung. Sie können nicht direkt auf diese Datei zugreifen."
|
||||||
|
|||||||
Binary file not shown.
@@ -156,3 +156,54 @@ msgstr "Last backup"
|
|||||||
|
|
||||||
msgid "Show"
|
msgid "Show"
|
||||||
msgstr "Show"
|
msgstr "Show"
|
||||||
|
|
||||||
|
msgid "HTTP"
|
||||||
|
msgstr "HTTP"
|
||||||
|
|
||||||
|
msgid "HTTPS"
|
||||||
|
msgstr "HTTPS"
|
||||||
|
|
||||||
|
msgid "API Error"
|
||||||
|
msgstr "API Error"
|
||||||
|
|
||||||
|
msgid "Unknown"
|
||||||
|
msgstr "Unknown"
|
||||||
|
|
||||||
|
msgid "Asset Definition"
|
||||||
|
msgstr "Asset Definition"
|
||||||
|
|
||||||
|
msgid "Legacy"
|
||||||
|
msgstr "Legacy"
|
||||||
|
|
||||||
|
msgid "UrBackup Servers"
|
||||||
|
msgstr "UrBackup Servers"
|
||||||
|
|
||||||
|
msgid "Invalid parameters"
|
||||||
|
msgstr "Invalid parameters"
|
||||||
|
|
||||||
|
msgid "Item type not enabled for UrBackup"
|
||||||
|
msgstr "Item type not enabled for UrBackup"
|
||||||
|
|
||||||
|
msgid "No server selected"
|
||||||
|
msgstr "No server selected"
|
||||||
|
|
||||||
|
msgid "Asset is already linked to a server"
|
||||||
|
msgstr "Asset is already linked to a server"
|
||||||
|
|
||||||
|
msgid "Failed to link asset to server"
|
||||||
|
msgstr "Failed to link asset to server"
|
||||||
|
|
||||||
|
msgid "Failed to disconnect asset from server"
|
||||||
|
msgstr "Failed to disconnect asset from server"
|
||||||
|
|
||||||
|
msgid "No permission"
|
||||||
|
msgstr "No permission"
|
||||||
|
|
||||||
|
msgid "Invalid server ID"
|
||||||
|
msgstr "Invalid server ID"
|
||||||
|
|
||||||
|
msgid "Server not found"
|
||||||
|
msgstr "Server not found"
|
||||||
|
|
||||||
|
msgid "Sorry. You cannot access this file directly."
|
||||||
|
msgstr "Sorry. You cannot access this file directly."
|
||||||
|
|||||||
Binary file not shown.
@@ -156,3 +156,54 @@ msgstr "Ultimo backup"
|
|||||||
|
|
||||||
msgid "Show"
|
msgid "Show"
|
||||||
msgstr "Mostra"
|
msgstr "Mostra"
|
||||||
|
|
||||||
|
msgid "HTTP"
|
||||||
|
msgstr "HTTP"
|
||||||
|
|
||||||
|
msgid "HTTPS"
|
||||||
|
msgstr "HTTPS"
|
||||||
|
|
||||||
|
msgid "API Error"
|
||||||
|
msgstr "Errore API"
|
||||||
|
|
||||||
|
msgid "Unknown"
|
||||||
|
msgstr "Sconosciuto"
|
||||||
|
|
||||||
|
msgid "Asset Definition"
|
||||||
|
msgstr "Definizione asset"
|
||||||
|
|
||||||
|
msgid "Legacy"
|
||||||
|
msgstr "Legacy"
|
||||||
|
|
||||||
|
msgid "UrBackup Servers"
|
||||||
|
msgstr "Server UrBackup"
|
||||||
|
|
||||||
|
msgid "Invalid parameters"
|
||||||
|
msgstr "Parametri non validi"
|
||||||
|
|
||||||
|
msgid "Item type not enabled for UrBackup"
|
||||||
|
msgstr "Tipo oggetto non abilitato per UrBackup"
|
||||||
|
|
||||||
|
msgid "No server selected"
|
||||||
|
msgstr "Nessun server selezionato"
|
||||||
|
|
||||||
|
msgid "Asset is already linked to a server"
|
||||||
|
msgstr "L'asset è già collegato a un server"
|
||||||
|
|
||||||
|
msgid "Failed to link asset to server"
|
||||||
|
msgstr "Collegamento asset al server fallito"
|
||||||
|
|
||||||
|
msgid "Failed to disconnect asset from server"
|
||||||
|
msgstr "Disconnessione asset dal server fallita"
|
||||||
|
|
||||||
|
msgid "No permission"
|
||||||
|
msgstr "Nessun permesso"
|
||||||
|
|
||||||
|
msgid "Invalid server ID"
|
||||||
|
msgstr "ID server non valido"
|
||||||
|
|
||||||
|
msgid "Server not found"
|
||||||
|
msgstr "Server non trovato"
|
||||||
|
|
||||||
|
msgid "Sorry. You cannot access this file directly."
|
||||||
|
msgstr "Spiacenti. Non puoi accedere direttamente a questo file."
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
// Force OPcache to reload this file when accessed via web
|
// Force OPcache to reload this file when accessed via web
|
||||||
if (PHP_SAPI !== 'cli' && function_exists('opcache_invalidate')) {
|
if (PHP_SAPI !== 'cli' && function_exists('opcache_invalidate')) {
|
||||||
opcache_invalidate(__FILE__, true);
|
opcache_invalidate(__FILE__, true);
|
||||||
@@ -97,7 +99,7 @@ function plugin_version_urbackup(): array
|
|||||||
return [
|
return [
|
||||||
'name' => __('UrBackup', 'urbackup'),
|
'name' => __('UrBackup', 'urbackup'),
|
||||||
'version' => PLUGIN_URBACKUP_VERSION,
|
'version' => PLUGIN_URBACKUP_VERSION,
|
||||||
'author' => 'Finstral',
|
'author' => 'Mariano Benzi',
|
||||||
'license' => 'GPL-2.0-or-later',
|
'license' => 'GPL-2.0-or-later',
|
||||||
'homepage' => '',
|
'homepage' => '',
|
||||||
'requirements' => [
|
'requirements' => [
|
||||||
|
|||||||
+44
-16
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
* UrBackup plugin for GLPI
|
* UrBackup plugin for GLPI
|
||||||
@@ -63,7 +65,7 @@ class AssetTab extends CommonDBTM
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::createTabEntry(__('UrBackup', 'urbackup'), 0, null, 'ti ti-cloud-upload');
|
return self::createTabEntry(__('UrBackup', 'urbackup'), 0, null, 'ti ti-cloud-up');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -324,15 +326,42 @@ 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>";
|
$canWrite = Session::haveRight(self::$rightname, UPDATE) || Session::haveRight(self::$rightname, CREATE);
|
||||||
|
|
||||||
|
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>';
|
||||||
|
if ($canWrite) {
|
||||||
|
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>";
|
if ($canWrite) {
|
||||||
self::showActionsSection($item, $server, $link, $api_data);
|
echo '<div class="tab-pane fade" id="actions" role="tabpanel">';
|
||||||
|
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>";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,17 +456,6 @@ class AssetTab extends CommonDBTM
|
|||||||
echo "<table class='tab_cadre_fixe'>";
|
echo "<table class='tab_cadre_fixe'>";
|
||||||
echo "<tr><th colspan='2'>" . htmlspecialchars(__('Available actions', 'urbackup')) . "</th></tr>";
|
echo "<tr><th colspan='2'>" . htmlspecialchars(__('Available actions', 'urbackup')) . "</th></tr>";
|
||||||
|
|
||||||
if (!Profile::canCurrentUser(UPDATE) && !Profile::canCurrentUser(CREATE)) {
|
|
||||||
echo "<tr class='tab_bg_1'>";
|
|
||||||
echo "<td colspan='2'>";
|
|
||||||
echo htmlspecialchars(__('You do not have permission for UrBackup actions.', 'urbackup'));
|
|
||||||
echo "</td>";
|
|
||||||
echo "</tr>";
|
|
||||||
echo "</table>";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$api_data['client_found'] && Profile::canCurrentUser(CREATE)) {
|
if (!$api_data['client_found'] && Profile::canCurrentUser(CREATE)) {
|
||||||
echo "<tr class='tab_bg_1'>";
|
echo "<tr class='tab_bg_1'>";
|
||||||
echo "<td>" . htmlspecialchars(__('Create client in UrBackup', 'urbackup')) . "</td>";
|
echo "<td>" . htmlspecialchars(__('Create client in UrBackup', 'urbackup')) . "</td>";
|
||||||
@@ -465,10 +483,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>";
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -268,7 +268,7 @@ class Config extends CommonDBTM
|
|||||||
'checked' => $is_default,
|
'checked' => $is_default,
|
||||||
]);
|
]);
|
||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "<td><span class='badge bg-info'>Asset Definition</span></td>";
|
echo "<td><span class='badge bg-info'>" . htmlspecialchars(__('Asset Definition', 'urbackup')) . "</span></td>";
|
||||||
} else {
|
} else {
|
||||||
// Legacy type
|
// Legacy type
|
||||||
echo "<td>";
|
echo "<td>";
|
||||||
@@ -278,7 +278,7 @@ class Config extends CommonDBTM
|
|||||||
]);
|
]);
|
||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "<td>" . ($is_default ? htmlspecialchars(__('Yes', 'urbackup')) : '') . "</td>";
|
echo "<td>" . ($is_default ? htmlspecialchars(__('Yes', 'urbackup')) : '') . "</td>";
|
||||||
echo "<td><span class='badge bg-secondary'>Legacy</span></td>";
|
echo "<td><span class='badge bg-secondary'>" . htmlspecialchars(__('Legacy', 'urbackup')) . "</span></td>";
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
* UrBackup plugin for GLPI
|
* UrBackup plugin for GLPI
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ class Profile extends \Profile
|
|||||||
|
|
||||||
public static function getIcon()
|
public static function getIcon()
|
||||||
{
|
{
|
||||||
return 'ti ti-server';
|
return 'ti ti-cloud-up';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0)
|
public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0)
|
||||||
|
|||||||
+446
-47
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
* UrBackup plugin for GLPI
|
* UrBackup plugin for GLPI
|
||||||
@@ -12,9 +14,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
|
||||||
{
|
{
|
||||||
@@ -151,7 +156,7 @@ class Server extends CommonDBTM
|
|||||||
if (self::canView()) {
|
if (self::canView()) {
|
||||||
$menu['title'] = self::getMenuName();
|
$menu['title'] = self::getMenuName();
|
||||||
$menu['page'] = self::getSearchURL(false);
|
$menu['page'] = self::getSearchURL(false);
|
||||||
$menu['icon'] = 'ti ti-server';
|
$menu['icon'] = 'ti ti-cloud-up';
|
||||||
|
|
||||||
$menu['links']['search'] = self::getSearchURL(false);
|
$menu['links']['search'] = self::getSearchURL(false);
|
||||||
|
|
||||||
@@ -292,15 +297,17 @@ class Server extends CommonDBTM
|
|||||||
'datatype' => 'datetime',
|
'datatype' => 'datetime',
|
||||||
];
|
];
|
||||||
|
|
||||||
$tab[] = [
|
if (Session::haveRight(self::$rightname, UPDATE)) {
|
||||||
'id' => 13,
|
$tab[] = [
|
||||||
'table' => self::getTable(),
|
'id' => 13,
|
||||||
'field' => 'id',
|
'table' => self::getTable(),
|
||||||
'name' => __('View', 'urbackup'),
|
'field' => 'id',
|
||||||
'massiveaction' => false,
|
'name' => __('View', 'urbackup'),
|
||||||
'datatype' => 'raw',
|
'massiveaction' => false,
|
||||||
'searchtype' => 'view',
|
'datatype' => 'raw',
|
||||||
];
|
'searchtype' => 'view',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return $tab;
|
return $tab;
|
||||||
}
|
}
|
||||||
@@ -324,7 +331,14 @@ class Server extends CommonDBTM
|
|||||||
|
|
||||||
$this->initForm($ID, $options);
|
$this->initForm($ID, $options);
|
||||||
$this->showFormHeader($options);
|
$this->showFormHeader($options);
|
||||||
|
$this->showFormFields($ID > 0 ? (int) $ID : null);
|
||||||
|
$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>";
|
||||||
@@ -374,8 +388,8 @@ class Server extends CommonDBTM
|
|||||||
Dropdown::showFromArray(
|
Dropdown::showFromArray(
|
||||||
'protocol',
|
'protocol',
|
||||||
[
|
[
|
||||||
'http' => 'HTTP',
|
'http' => __('HTTP', 'urbackup'),
|
||||||
'https' => 'HTTPS',
|
'https' => __('HTTPS', 'urbackup'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'value' => $this->fields['protocol'] ?? 'http',
|
'value' => $this->fields['protocol'] ?? 'http',
|
||||||
@@ -419,21 +433,31 @@ class Server extends CommonDBTM
|
|||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
|
|
||||||
|
$canUpdate = Session::haveRight(self::$rightname, UPDATE);
|
||||||
|
|
||||||
echo "<tr class='tab_bg_1'>";
|
echo "<tr class='tab_bg_1'>";
|
||||||
echo "<td>" . htmlspecialchars(__('API username', 'urbackup')) . "</td>";
|
echo "<td>" . htmlspecialchars(__('API username', 'urbackup')) . "</td>";
|
||||||
echo "<td>";
|
echo "<td>";
|
||||||
echo Html::input('api_username', [
|
if ($canUpdate) {
|
||||||
'value' => $this->fields['api_username'] ?? '',
|
echo Html::input('api_username', [
|
||||||
'size' => 40,
|
'value' => $this->fields['api_username'] ?? '',
|
||||||
'autocomplete' => 'off',
|
'size' => 40,
|
||||||
]);
|
'autocomplete' => 'off',
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
echo htmlspecialchars($this->fields['api_username'] ?? '');
|
||||||
|
}
|
||||||
echo "</td>";
|
echo "</td>";
|
||||||
|
|
||||||
echo "<td>" . htmlspecialchars(__('API password', 'urbackup')) . "</td>";
|
echo "<td>" . htmlspecialchars(__('API password', 'urbackup')) . "</td>";
|
||||||
echo "<td>";
|
echo "<td>";
|
||||||
echo "<input type='password' name='api_password' value='" .
|
if ($canUpdate) {
|
||||||
htmlspecialchars((string) ($this->fields['api_password'] ?? '')) .
|
echo "<input type='password' name='api_password' value='" .
|
||||||
"' autocomplete='new-password'>";
|
htmlspecialchars((string) ($this->fields['api_password'] ?? '')) .
|
||||||
|
"' autocomplete='new-password'>";
|
||||||
|
} else {
|
||||||
|
echo '******';
|
||||||
|
}
|
||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
|
|
||||||
@@ -464,7 +488,7 @@ class Server extends CommonDBTM
|
|||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
|
|
||||||
$apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
$apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
||||||
echo "<tr class='tab_bg_1'>";
|
echo "<tr class='tab_bg_1'>";
|
||||||
echo "<td>" . htmlspecialchars(__('API connection status', 'urbackup')) . "<br><small class='text-muted'>" . htmlspecialchars(__('Click Save to test connection', 'urbackup')) . "</small></td>";
|
echo "<td>" . htmlspecialchars(__('API connection status', 'urbackup')) . "<br><small class='text-muted'>" . htmlspecialchars(__('Click Save to test connection', 'urbackup')) . "</small></td>";
|
||||||
echo "<td colspan='3'>";
|
echo "<td colspan='3'>";
|
||||||
@@ -479,10 +503,6 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->showFormButtons($options);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -542,6 +562,26 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
|
|
||||||
public function prepareInputForAdd(mixed $input): mixed
|
public function prepareInputForAdd(mixed $input): mixed
|
||||||
{
|
{
|
||||||
|
if (!is_array($input)) {
|
||||||
|
return $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($input['port']) || $input['port'] === '' || $input['port'] === null) {
|
||||||
|
$input['port'] = 55414;
|
||||||
|
}
|
||||||
|
if (!isset($input['protocol']) || $input['protocol'] === '') {
|
||||||
|
$input['protocol'] = 'http';
|
||||||
|
}
|
||||||
|
if (!isset($input['is_active']) || $input['is_active'] === '' || $input['is_active'] === null) {
|
||||||
|
$input['is_active'] = 1;
|
||||||
|
}
|
||||||
|
if (!isset($input['is_recursive']) || $input['is_recursive'] === '' || $input['is_recursive'] === null) {
|
||||||
|
$input['is_recursive'] = 0;
|
||||||
|
}
|
||||||
|
if (!isset($input['ignore_ssl']) || $input['ignore_ssl'] === '' || $input['ignore_ssl'] === null) {
|
||||||
|
$input['ignore_ssl'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->prepareInputForUpdate($input);
|
return $this->prepareInputForUpdate($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,6 +591,16 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
return $input;
|
return $input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($input['port']) && ($input['port'] === '' || $input['port'] === null)) {
|
||||||
|
$input['port'] = 55414;
|
||||||
|
}
|
||||||
|
if (isset($input['protocol']) && $input['protocol'] === '') {
|
||||||
|
$input['protocol'] = 'http';
|
||||||
|
}
|
||||||
|
if (isset($input['ignore_ssl']) && ($input['ignore_ssl'] === '' || $input['ignore_ssl'] === null)) {
|
||||||
|
$input['ignore_ssl'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($input['id']) && (int) $input['id'] > 0) {
|
if (!empty($input['id']) && (int) $input['id'] > 0) {
|
||||||
$server = new self();
|
$server = new self();
|
||||||
if ($server->getFromDB((int) $input['id'])) {
|
if ($server->getFromDB((int) $input['id'])) {
|
||||||
@@ -780,7 +830,7 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
echo '<div class="alert alert-danger">';
|
echo '<div class="alert alert-danger">';
|
||||||
echo 'API Error: ' . htmlspecialchars($e->getMessage());
|
echo htmlspecialchars(__('API Error', 'urbackup')) . ': ' . htmlspecialchars($e->getMessage());
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -789,7 +839,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 +889,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>';
|
||||||
@@ -949,6 +1004,8 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$canWrite = Session::haveRight(self::$rightname, UPDATE) || Session::haveRight(self::$rightname, CREATE);
|
||||||
|
|
||||||
echo '<table class="table table-striped table-hover">';
|
echo '<table class="table table-striped table-hover">';
|
||||||
echo '<thead>';
|
echo '<thead>';
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
@@ -957,13 +1014,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>';
|
if ($canWrite) {
|
||||||
|
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');
|
$clientName = (string) ($uc['name'] ?? __('Unknown', 'urbackup'));
|
||||||
$clientNameLower = strtolower($clientName);
|
$clientNameLower = strtolower($clientName);
|
||||||
|
|
||||||
$online = $uc['online'] ?? null;
|
$online = $uc['online'] ?? null;
|
||||||
@@ -982,27 +1041,367 @@ $apiStatus = (int) ($this->fields['last_api_status'] ?? 0);
|
|||||||
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 ($canWrite) {
|
||||||
if (isset($linkableAssets[$clientNameLower])) {
|
echo '<td>';
|
||||||
$match = $linkableAssets[$clientNameLower];
|
if (isset($linkableAssets[$clientNameLower])) {
|
||||||
$formAction = PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php';
|
$match = $linkableAssets[$clientNameLower];
|
||||||
echo '<form method="post" action="' . htmlspecialchars($formAction) . '" class="d-inline">';
|
$formAction = PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php';
|
||||||
echo Html::hidden('_glpi_csrf_token', ['value' => Session::getNewCSRFToken()]);
|
echo '<form method="post" action="' . htmlspecialchars($formAction) . '" class="d-inline">';
|
||||||
echo Html::hidden('itemtype', ['value' => $match['itemtype']]);
|
echo Html::hidden('_glpi_csrf_token', ['value' => Session::getNewCSRFToken()]);
|
||||||
echo Html::hidden('items_id', ['value' => $match['items_id']]);
|
echo Html::hidden('itemtype', ['value' => $match['itemtype']]);
|
||||||
echo Html::hidden('id', ['value' => (int) $server->fields['id']]);
|
echo Html::hidden('items_id', ['value' => $match['items_id']]);
|
||||||
echo '<button type="submit" name="link_asset" value="1" class="btn btn-primary btn-sm">';
|
echo Html::hidden('id', ['value' => (int) $server->fields['id']]);
|
||||||
echo htmlspecialchars(__('Connect'));
|
echo '<button type="submit" name="link_asset" value="1" class="btn btn-primary btn-sm">';
|
||||||
echo '</button>';
|
echo htmlspecialchars(__('Connect'));
|
||||||
Html::closeForm();
|
echo '</button>';
|
||||||
} else {
|
Html::closeForm();
|
||||||
echo '<span class="text-muted">—</span>';
|
} else {
|
||||||
|
echo '<span class="text-muted">—</span>';
|
||||||
|
}
|
||||||
|
echo '</td>';
|
||||||
}
|
}
|
||||||
echo '</td>';
|
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '</tbody>';
|
echo '</tbody>';
|
||||||
echo '</table>';
|
echo '</table>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function showMissingClientsTab(Server $server): void
|
||||||
|
{
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
$canWrite = Session::haveRight(self::$rightname, UPDATE) || Session::haveRight(self::$rightname, CREATE);
|
||||||
|
|
||||||
|
$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::getAssetGroupName($itemtype, $assetId, $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;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<div class="d-flex justify-content-end mb-2">';
|
||||||
|
echo '<input type="text" id="missing-search" class="form-control form-control-sm" placeholder="' . htmlspecialchars(__('Search...', 'urbackup')) . '" style="width:250px">';
|
||||||
|
echo '</div>';
|
||||||
|
|
||||||
|
$formAction = PLUGIN_URBACKUP_WEB_DIR . '/front/server.form.php';
|
||||||
|
|
||||||
|
echo '<table id="missing-table" class="table table-striped table-hover">';
|
||||||
|
echo '<thead><tr>';
|
||||||
|
echo '<th class="sortable" data-col="0">' . htmlspecialchars(__('Name')) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
echo '<th class="sortable" data-col="1">' . htmlspecialchars(Entity::getTypeName(1)) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
echo '<th class="sortable" data-col="2">' . htmlspecialchars(Location::getTypeName(1)) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
echo '<th class="sortable" data-col="3">' . htmlspecialchars(__('Inventory number')) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
echo '<th class="sortable" data-col="4">' . htmlspecialchars(__('IP address', 'urbackup')) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
echo '<th class="sortable" data-col="5">' . htmlspecialchars(State::getTypeName(1)) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
echo '<th class="sortable" data-col="6">' . htmlspecialchars(User::getTypeName(1)) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
echo '<th class="sortable" data-col="7">' . htmlspecialchars(Group::getTypeName(1)) . ' <span class="sort-arrow"></span></th>';
|
||||||
|
if ($canWrite) {
|
||||||
|
echo '<th data-col="8">' . htmlspecialchars(__('Actions', 'urbackup')) . '</th>';
|
||||||
|
}
|
||||||
|
echo '</tr></thead>';
|
||||||
|
echo '<tbody>';
|
||||||
|
|
||||||
|
foreach ($missingAssets as $asset) {
|
||||||
|
$item = new $asset['itemtype']();
|
||||||
|
$itemLink = '';
|
||||||
|
if ($item instanceof CommonDBTM && $item->getFromDB($asset['items_id'])) {
|
||||||
|
$itemLink = $item->getLinkURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<tr>';
|
||||||
|
echo '<td>';
|
||||||
|
if ($itemLink !== '') {
|
||||||
|
echo '<a href="' . htmlspecialchars($itemLink) . '">' . htmlspecialchars($asset['name']) . '</a>';
|
||||||
|
} else {
|
||||||
|
echo htmlspecialchars($asset['name']);
|
||||||
|
}
|
||||||
|
echo '</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>';
|
||||||
|
if ($canWrite) {
|
||||||
|
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>';
|
||||||
|
|
||||||
|
echo <<<'JAVASCRIPT'
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var sortDir = {};
|
||||||
|
$('#missing-table th.sortable').on('click', function () {
|
||||||
|
var col = parseInt($(this).data('col'));
|
||||||
|
var $table = $('#missing-table');
|
||||||
|
var $tbody = $table.find('tbody');
|
||||||
|
var rows = $tbody.find('tr').get();
|
||||||
|
|
||||||
|
var dir = sortDir[col] === 'asc' ? 'desc' : 'asc';
|
||||||
|
sortDir[col] = dir;
|
||||||
|
|
||||||
|
rows.sort(function (a, b) {
|
||||||
|
var aVal = $(a).children('td').eq(col).text().trim().toLowerCase();
|
||||||
|
var bVal = $(b).children('td').eq(col).text().trim().toLowerCase();
|
||||||
|
if (aVal < bVal) return dir === 'asc' ? -1 : 1;
|
||||||
|
if (aVal > bVal) return dir === 'asc' ? 1 : -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
$.each(rows, function (i, row) { $tbody.append(row); });
|
||||||
|
|
||||||
|
$table.find('th .sort-arrow').text('');
|
||||||
|
$(this).find('.sort-arrow').text(dir === 'asc' ? '\u25B2' : '\u25BC');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#missing-search').on('keyup', function () {
|
||||||
|
var val = $(this).val().toLowerCase();
|
||||||
|
$('#missing-table tbody tr').each(function () {
|
||||||
|
var match = false;
|
||||||
|
$(this).children('td').each(function () {
|
||||||
|
if ($(this).text().toLowerCase().indexOf(val) > -1) {
|
||||||
|
match = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(this).toggle(match);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
JAVASCRIPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
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['completename'] ?? $obj->fields['name'] ?? '');
|
||||||
|
} else {
|
||||||
|
$cache[$id] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $cache[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getAssetGroupName(string $itemtype, int $items_id, array &$cache): string
|
||||||
|
{
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
$iterator = $DB->request([
|
||||||
|
'FROM' => 'glpi_groups_items',
|
||||||
|
'WHERE' => [
|
||||||
|
'itemtype' => $itemtype,
|
||||||
|
'items_id' => $items_id,
|
||||||
|
'type' => \Group_Item::GROUP_TYPE_NORMAL,
|
||||||
|
],
|
||||||
|
'LIMIT' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($iterator as $row) {
|
||||||
|
$groupId = (int) ($row['groups_id'] ?? 0);
|
||||||
|
if ($groupId > 0) {
|
||||||
|
return self::getCachedName('Group', $groupId, $cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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 '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+6
-14
@@ -79,7 +79,6 @@ class ServerAsset extends CommonDBTM
|
|||||||
}
|
}
|
||||||
|
|
||||||
$table = self::getTable();
|
$table = self::getTable();
|
||||||
$date = $_SESSION['glpi_currenttime'] ?? date('Y-m-d H:i:s');
|
|
||||||
|
|
||||||
$existing = self::getLinkForAsset($itemtype, $items_id, false);
|
$existing = self::getLinkForAsset($itemtype, $items_id, false);
|
||||||
|
|
||||||
@@ -88,10 +87,6 @@ class ServerAsset extends CommonDBTM
|
|||||||
$table,
|
$table,
|
||||||
[
|
[
|
||||||
'plugin_urbackup_servers_id' => $server_id,
|
'plugin_urbackup_servers_id' => $server_id,
|
||||||
'client_name' => (string) ($item->fields['name'] ?? ''),
|
|
||||||
'client_ip' => self::extractAssetIp($item),
|
|
||||||
'is_active' => 1,
|
|
||||||
'date_mod' => $date,
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => (int) $existing['id'],
|
'id' => (int) $existing['id'],
|
||||||
@@ -243,43 +238,40 @@ class ServerAsset extends CommonDBTM
|
|||||||
|
|
||||||
echo "<div class='center'>";
|
echo "<div class='center'>";
|
||||||
echo "<table class='tab_cadre_fixehov'>";
|
echo "<table class='tab_cadre_fixehov'>";
|
||||||
echo "<tr><th colspan='5'>" . htmlspecialchars(__('Linked assets', 'urbackup')) . "</th></tr>";
|
echo "<tr><th colspan='4'>" . htmlspecialchars(__('Linked assets', 'urbackup')) . "</th></tr>";
|
||||||
echo "<tr>";
|
echo "<tr>";
|
||||||
echo "<th>" . htmlspecialchars(__('Asset', 'urbackup')) . "</th>";
|
echo "<th>" . htmlspecialchars(__('Asset', 'urbackup')) . "</th>";
|
||||||
echo "<th>" . htmlspecialchars(__('Type')) . "</th>";
|
echo "<th>" . htmlspecialchars(__('Type')) . "</th>";
|
||||||
echo "<th>" . htmlspecialchars(__('IP address', 'urbackup')) . "</th>";
|
echo "<th>" . htmlspecialchars(__('IP address', 'urbackup')) . "</th>";
|
||||||
echo "<th>" . htmlspecialchars(__('Last file backup', 'urbackup')) . "</th>";
|
|
||||||
echo "<th>" . htmlspecialchars(__('Last image backup', 'urbackup')) . "</th>";
|
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
|
|
||||||
$iterator = $DB->request([
|
$iterator = $DB->request([
|
||||||
'FROM' => self::getTable(),
|
'FROM' => self::getTable(),
|
||||||
'WHERE' => [
|
'WHERE' => [
|
||||||
'plugin_urbackup_servers_id' => (int) $item->fields['id'],
|
'plugin_urbackup_servers_id' => (int) $item->fields['id'],
|
||||||
'is_active' => 1,
|
|
||||||
],
|
],
|
||||||
'ORDER' => 'client_name',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($iterator as $row) {
|
foreach ($iterator as $row) {
|
||||||
$asset_label = (string) $row['client_name'];
|
|
||||||
$itemtype = (string) $row['itemtype'];
|
$itemtype = (string) $row['itemtype'];
|
||||||
$items_id = (int) $row['items_id'];
|
$items_id = (int) $row['items_id'];
|
||||||
|
|
||||||
|
$asset_label = (string) $items_id;
|
||||||
|
$asset_ip = '';
|
||||||
|
|
||||||
if (class_exists($itemtype)) {
|
if (class_exists($itemtype)) {
|
||||||
$asset = new $itemtype();
|
$asset = new $itemtype();
|
||||||
|
|
||||||
if ($asset instanceof CommonDBTM && $asset->getFromDB($items_id)) {
|
if ($asset instanceof CommonDBTM && $asset->getFromDB($items_id)) {
|
||||||
$asset_label = $asset->getLink();
|
$asset_label = $asset->getLink();
|
||||||
|
$asset_ip = Server::getAssetIp($itemtype, $items_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "<tr class='tab_bg_1'>";
|
echo "<tr class='tab_bg_1'>";
|
||||||
echo "<td>" . $asset_label . "</td>";
|
echo "<td>" . $asset_label . "</td>";
|
||||||
echo "<td>" . htmlspecialchars($itemtype) . "</td>";
|
echo "<td>" . htmlspecialchars($itemtype) . "</td>";
|
||||||
echo "<td>" . htmlspecialchars((string) $row['client_ip']) . "</td>";
|
echo "<td>" . htmlspecialchars($asset_ip ?: '-') . "</td>";
|
||||||
echo "<td>" . htmlspecialchars((string) $row['last_file_backup']) . "</td>";
|
|
||||||
echo "<td>" . htmlspecialchars((string) $row['last_image_backup']) . "</td>";
|
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user