From c90506a25d00915a29a1c38a12dacd332b529d7f Mon Sep 17 00:00:00 2001
From: mariano
Date: Thu, 28 May 2026 11:57:47 +0200
Subject: [PATCH] versione pre-stable
---
AGENTS_OLD.MD | 66 --------
FIX_PERMISSIONS.sh | 27 ----
MEMORY.md | 13 +-
README.md | 147 ++++++++++++++----
ajax/server_test.php | 57 -------
composer copy.json | 23 ---
front/ajax.test.php | 59 --------
front/asset.form.php | 2 +
front/config.form.php | 2 +-
front/server.form.php | 2 +
front/server.php | 2 -
front/server.test.php | 64 --------
front/server.view.php | 42 ------
front/server_test.ajax.php | 4 +
front/test.button.php | 43 ------
install/install.php | 47 +++---
install/mysql/plugin_urbackup-empty.sql | 27 +---
js/urbackup.js | 87 -----------
remove_deprecated_files.sh | 11 --
removed/profile.form.php___ | 41 -----
setup.php | 2 +-
src/Command/TestApiCommand.php | 56 -------
src/Controller/AssetController.php | 191 ------------------------
src/Controller/ConfigController.php | 36 -----
src/Controller/ServerController.php | 109 --------------
templates/asset/asset_tab.html.twig | 69 ---------
templates/config/config.html.twig | 18 ---
templates/server/server_form.html.twig | 118 ---------------
templates/server/server_list.html.twig | 51 -------
29 files changed, 166 insertions(+), 1250 deletions(-)
delete mode 100644 AGENTS_OLD.MD
delete mode 100755 FIX_PERMISSIONS.sh
delete mode 100644 ajax/server_test.php
delete mode 100644 composer copy.json
delete mode 100644 front/ajax.test.php
delete mode 100644 front/server.test.php
delete mode 100644 front/server.view.php
delete mode 100644 front/test.button.php
delete mode 100644 js/urbackup.js
delete mode 100755 remove_deprecated_files.sh
delete mode 100644 removed/profile.form.php___
delete mode 100644 src/Command/TestApiCommand.php
delete mode 100644 src/Controller/AssetController.php
delete mode 100644 src/Controller/ConfigController.php
delete mode 100644 src/Controller/ServerController.php
delete mode 100644 templates/asset/asset_tab.html.twig
delete mode 100644 templates/config/config.html.twig
delete mode 100644 templates/server/server_form.html.twig
delete mode 100644 templates/server/server_list.html.twig
diff --git a/AGENTS_OLD.MD b/AGENTS_OLD.MD
deleted file mode 100644
index 4f21aa1..0000000
--- a/AGENTS_OLD.MD
+++ /dev/null
@@ -1,66 +0,0 @@
-# Istruzioni per lo Sviluppo PHP 8.3 & Symfony
-
-Sei un esperto Senior Developer specializzato in Symfony (6.4+) e PHP 8.3.
-
-## Regole del Codice (PHP 8.3)
-
-- Usa sempre la **Constructor Promotion** per la Dependency Injection.
-
-- Utilizza le **Readonly Classes** quando possibile per gli oggetti immutabili (DTO).
-
-- Applica **Typed Class Constants** (novità PHP 8.3).
-
-- Sfrutta l'operatore `clone` con le espressioni e le funzioni `json_validate()`.
-
-- Rigorosa tipizzazione: usa `declare(strict_types=1);` in ogni nuovo file.
-
-## Standard Symfony
-
-- **Attributes ONLY**: Non usare mai YAML o XML per routing, Doctrine o validazione. Usa solo PHP Attributes.
-
-- **Service Container**: Prediligi l'autowiring.
-
-- **Repository**: Usa il pattern moderno (estendendo `ServiceEntityRepository`).
-
-- **Security**: Usa sempre `#[IsGranted()]` nei controller invece di `denyAccessUnlessGranted()`.
-
-## Workflow di Risoluzione Errori
-
-1. Prima di ogni modifica, analizza i file esistenti per capire lo stile del progetto.
-
-2. Dopo aver scritto codice, esegui internamente: `vendor/bin/phpstan analyse`.
-
-3. Se ci sono errori di stile, correggi con: `vendor/bin/ecs check --fix`.
-
-4. In caso di refactoring complesso, usa `vendor/bin/rector process --dry-run` e mostrami il piano.
-
-## Memoria degli Errori
-
-- Leggi sempre il file `FIX_HISTORY.md` per non ripetere bug già risolti in passato.
-
-- Ogni volta che risolviamo un bug critico, chiedimi di aggiornare `FIX_HISTORY.md`.
-
-
-## Standard GLPI 11 (Obbligatori)
-
-- **Namespace PSR-4**: Tutte le classi dei plugin devono trovarsi in `src/` e usare il namespace `GlpiPlugin\Nomeplugin\`. La cartella `inc/` è deprecata.
-
-- **Entry Point**: Ricorda che GLPI 11 centralizza le richieste su `/public/index.php`. Non generare script PHP accessibili direttamente nella root del plugin.
-
-- **Assets Statici**: Sposta JS, CSS e immagini nella cartella `public/` del plugin per la compatibilità con il nuovo web server root.
-
-- **Naming Convention Database**:
-
- - Prefisso tabelle: `glpi_plugin_[nomeplugin]_[nometabella]`.
-
- - Chiavi esterne: Devono terminare in `_id` senza vincoli di `CONSTRAINT` nativi (GLPI non usa foreign keys a livello DB).
-
-- **Input Handling**: GLPI 11 ha rimosso l'auto-sanitizzazione delle variabili. Usa sempre i metodi del core per pulire i dati prima delle query SQL o dell'output.
-
-## Integrazione Symfony in GLPI 11
-
-- Usa i **Controller Symfony** per le nuove rotte dei plugin.
-
-- Sfrutta il **Twig Template Engine** situato in `templates/` per la UI.
-
-- Definisci i comandi CLI tramite il componente Console di Symfony.
diff --git a/FIX_PERMISSIONS.sh b/FIX_PERMISSIONS.sh
deleted file mode 100755
index b92df03..0000000
--- a/FIX_PERMISSIONS.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-# Fix file permissions for GLPI plugin
-echo "Fixing file permissions..."
-
-# Fix ownership
-sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/src/Server.php
-sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/src/Profile.php
-sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/src/MassiveAction.php
-sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/src/AssetTab.php
-sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/hook.php
-sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/setup.php
-
-# Replace hook.php with corrected version
-if [ -f /var/www/glpi/plugins/urbackup/hook_corrected.php ]; then
- sudo cp /var/www/glpi/plugins/urbackup/hook_corrected.php /var/www/glpi/plugins/urbackup/hook.php
- sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/hook.php
- rm /var/www/glpi/plugins/urbackup/hook_corrected.php
-fi
-
-# Fix all src/ files
-sudo chown www-data:www-data /var/www/glpi/plugins/urbackup/src/*.php
-
-echo "Permissions fixed. Now add declare(strict_types=1) to:"
-echo " - src/Server.php"
-echo " - src/Profile.php"
-echo " - src/MassiveAction.php"
-echo " - src/AssetTab.php"
diff --git a/MEMORY.md b/MEMORY.md
index 50a8402..2d4c43a 100644
--- a/MEMORY.md
+++ b/MEMORY.md
@@ -1,6 +1,6 @@
# MEMORY.md - Stato del Plugin UrBackup
-## Ultima modifica: 27/05/2026
+## Ultima modifica: 28/05/2026
## Performance - Asset Definition vs Computer
@@ -53,4 +53,13 @@ In una nuova installazione del plugin, i campi "API username" e "API password" n
2. **`Profile.php::installRights()`** — In assenza di sessione attiva (CLI), cerca il profilo "Super-Admin" tramite query diretta e gli assegna tutti i diritti.
## Versione
-- 0.6.1
+- 0.7.0
+
+## 0.7.0 — Pulizia, sicurezza e DB cleanup
+1. **CSRF hardening**: `Session::checkCSRF()` aggiunto su `asset.form.php`, `server.form.php`, `server_test.ajax.php`, `config.form.php`
+2. **File deprecati rimossi**: 12 file (composer copy, AGENTS_OLD.MD, js/, ajax/, front/test/view, FIX_PERMISSIONS.sh, removed/)
+3. **Dead code rimosso**: 3 Controller, 1 Command, 4 template Twig
+4. **DB migration**: DROP `glpi_plugin_urbackup_profiles` e `glpi_plugin_urbackup_assettypes`; add index `location_active` su servers; add `date_creation`/`date_mod` su serverassets
+5. **SQL schema pulito**: Rimosse tabelle legacy dall'empty.sql
+6. **PHP lint warnings**: Rimosse `use Html;` e `use Search;` superflue
+7. **README.md** creato
diff --git a/README.md b/README.md
index edcc639..63ed461 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,130 @@
-# UrBackup Plugin for GLPI 11
+# UrBackup plugin for GLPI 11
-Plugin **UrBackup** per GLPI 11, sviluppato in PHP 8.3, che consente la gestione
-centralizzata dei server UrBackup e dei client direttamente dall’interfaccia GLPI.
+[](https://glpi-project.org)
+[](https://php.net)
+[](LICENSE)
-Il plugin permette di:
-- collegare asset GLPI (Computer e altri asset) ai server UrBackup;
-- visualizzare lo stato dei backup;
-- eseguire azioni UrBackup (backup, gestione client, impostazioni);
-- gestire i server UrBackup da GLPI;
-- integrare ACL complete per profili GLPI;
-- supportare multi‑lingua (IT / EN / DE).
+Integrate [UrBackup](https://www.urbackup.org/) backup server management directly into GLPI. Monitor clients, manage backups, and link assets to UrBackup servers from within GLPI's asset management interface.
----
+## Features
-## ✅ Compatibilità
+- **Server management** – Register UrBackup servers by location; test API connectivity.
+- **Asset linking** – Link Computers (and other GLPI 11 asset types) to UrBackup clients.
+- **Backup actions** – Start file/image incremental and full backups directly from the asset form.
+- **Client lifecycle** – Create, rename, and delete UrBackup clients from GLPI.
+- **Internet mode** – Toggle internet mode and configure default backup directories per asset.
+- **Capacity system** – Native GLPI 11 integration via `UrBackupCapacity`; enable per Asset Definition.
+- **Location-aware** – Auto-match assets to servers based on location hierarchy.
+- **Massive actions** – Link/unlink assets to servers in bulk.
-| Componente | Versione |
-|-----------|----------|
-| GLPI | 11.x |
-| PHP | ≥ 8.3 |
-| Database | MySQL / MariaDB (GLPI standard) |
+## Requirements
----
+| Component | Version |
+|-----------|---------|
+| **GLPI** | >= 11.0.6, < 12.0.0 |
+| **PHP** | >= 8.3.0 (8.4 supported) |
+| **Database** | MySQL 5.7+ / MariaDB 10.5+ |
-## ✅ Funzionalità principali
+## Installation
-### 🔧 Configurazione plugin
-- Percorso: **Configurazione → Plugin → UrBackup**
-- Asset supportati:
- - Computer (sempre attivo)
- - Altri asset GLPI configurabili
-- Attivazione automatica tab e massive action sugli asset abilitati
+1. **Download** the plugin and extract it to `GLPI_ROOT/plugins/urbackup/`
+2. **Install** via GLPI web interface or CLI:
----
+```bash
+php bin/console glpi:plugin:install urbackup
+php bin/console glpi:plugin:activate urbackup
+```
-### 🗄️ Gestione server UrBackup
+3. **Configure rights** – Go to *Administration > Profiles*, select a profile, and set *UrBackup* rights (READ / UPDATE / CREATE / DELETE / PURGE).
+4. **Add servers** – Navigate to *Admin > UrBackup servers* and register your UrBackup instances.
+5. **Enable capacity** – Go to *Config > Asset definitions*, open an asset type, and enable *UrBackup* in the Capacities tab.
+
+## Usage
+
+### Linking assets to a server
+
+- Open an asset (Computer, etc.) and go to the **UrBackup** tab.
+- Select a server from the dropdown and click **Connect**.
+- The asset appears in the server's *Linked clients* tab and backup actions become available.
+
+### Starting a backup
+
+1. Open a linked asset and go to its UrBackup tab.
+2. Click **Start file backup** (incremental) or **Start image backup**.
+3. Monitor progress in the UrBackup server web interface.
+
+### Managing servers
+
+- **Add**: *Admin > UrBackup servers > Add*
+- **Edit**: Click a server name or the edit icon.
+- **Test API**: The plugin auto-tests the API when saving; status is shown in the list.
+
+## Permissions
+
+| Right | Description |
+|-------------|-------------|
+| `READ` | View servers and asset backup status |
+| `UPDATE` | Edit servers, start backups, toggle internet mode |
+| `CREATE` | Add new servers, create clients |
+| `DELETE` | Disconnect assets from servers |
+| `PURGE` | Delete clients from UrBackup server |
+
+## Development
+
+```bash
+# Lint
+php -l src/*.php front/*.php
+
+# Type checking (requires PHPStan)
+vendor/bin/phpstan analyse --level 8 src/
+
+# Database migration testing
+# Install/uninstall/reinstall via CLI:
+php bin/console glpi:plugin:install urbackup
+php bin/console glpi:plugin:uninstall urbackup
+```
+
+## Project Structure
+
+```
+plugin_urbackup/
+├── front/ # Entry points (form handlers, AJAX endpoints)
+├── install/ # DB schema (mysql/) and install/uninstall scripts
+├── public/ # Static assets (CSS, JS)
+├── src/ # PHP classes (PSR-4: Plugin\Urbackup\)
+│ ├── AssetTab.php
+│ ├── Capacity/ # GLPI 11 capacity integration
+│ ├── Config.php
+│ ├── LocationHelper.php
+│ ├── Profile.php
+│ ├── Server.php
+│ ├── ServerAsset.php
+│ └── UrbackupApiClient.php
+├── templates/ # Twig templates
+├── setup.php # Plugin metadata, hooks, class registration
+├── hook.php # Install/upgrade/uninstall + massive actions
+└── README.md
+```
+
+## Changelog
+
+### 0.7.0
+- Dropped legacy `glpi_plugin_urbackup_profiles` and `glpi_plugin_urbackup_assettypes` tables
+- Added composite index `(locations_id, is_active)` on servers table
+- Added `date_creation`/`date_mod` columns to serverassets table
+- Removed deprecated files and dead Symfony controller code
+- CSRF hardening on all POST handlers
+- Bumped minimum PHP to 8.3
+
+### 0.6.0
+- GLPI 11 compatibility with Asset Definition capacity system
+- Migrated from Symfony to native GLPI form handling
+- Added location-aware server matching
+
+### 0.5.0
+- Initial GLPI 10 compatibility
+- Profile-based rights management
+
+## License
+
+GNU General Public License v2.0 or later. See [LICENSE](LICENSE).
diff --git a/ajax/server_test.php b/ajax/server_test.php
deleted file mode 100644
index 7932e20..0000000
--- a/ajax/server_test.php
+++ /dev/null
@@ -1,57 +0,0 @@
- false, 'message' => 'No permission']);
- exit;
-}
-
-$server_id = (int) ($_POST['id'] ?? $_GET['id'] ?? 0);
-
-if ($server_id <= 0) {
- echo json_encode(['success' => false, 'message' => 'Invalid server ID']);
- exit;
-}
-
-$server = new GlpiPlugin\Urbackup\Server();
-
-if (!$server->getFromDB($server_id)) {
- echo json_encode(['success' => false, 'message' => 'Server not found']);
- exit;
-}
-
-try {
- $client = new GlpiPlugin\Urbackup\UrbackupApiClient($server);
- $result = $client->testConnection();
-
- $server->update([
- 'id' => $server_id,
- 'last_api_status' => $result['success'] ? 1 : 0,
- 'last_api_message' => $result['message'],
- 'last_api_check' => date('Y-m-d H:i:s'),
- ]);
-
- echo json_encode($result);
-} catch (Throwable $e) {
- echo json_encode(['success' => false, 'message' => $e->getMessage()]);
-}
diff --git a/composer copy.json b/composer copy.json
deleted file mode 100644
index 0a98ead..0000000
--- a/composer copy.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "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"
- }
- }
-}
\ No newline at end of file
diff --git a/front/ajax.test.php b/front/ajax.test.php
deleted file mode 100644
index 4183ad2..0000000
--- a/front/ajax.test.php
+++ /dev/null
@@ -1,59 +0,0 @@
- false, 'message' => 'No permission']);
- exit;
-}
-
-$server_id = (int) (($_GET['id'] ?? $_POST['id'] ?? 0));
-
-if ($server_id <= 0) {
- echo json_encode(['success' => false, 'message' => 'Invalid server ID']);
- exit;
-}
-
-// Load plugin classes
-$classes = ['Server', 'UrbackupApiClient'];
-foreach ($classes as $class) {
- $file = PLUGIN_URBACKUP_DIR . '/src/' . $class . '.php';
- if (file_exists($file)) {
- require_once $file;
- }
-}
-
-$server = new \GlpiPlugin\Urbackup\Server();
-
-if (!$server->getFromDB($server_id)) {
- echo json_encode(['success' => false, 'message' => 'Server not found']);
- exit;
-}
-
-try {
- $client = new \GlpiPlugin\Urbackup\UrbackupApiClient($server);
- $result = $client->testConnection();
-
- $server->update([
- 'id' => $server_id,
- 'last_api_status' => $result['success'] ? 1 : 0,
- 'last_api_message' => $result['message'],
- 'last_api_check' => date('Y-m-d H:i:s'),
- ]);
-
- echo json_encode($result);
-} catch (Throwable $e) {
- echo json_encode(['success' => false, 'message' => $e->getMessage()]);
-}
diff --git a/front/asset.form.php b/front/asset.form.php
index db184e4..4d2a845 100644
--- a/front/asset.form.php
+++ b/front/asset.form.php
@@ -41,6 +41,8 @@ if (!$item || !$item->getFromDB($items_id)) {
Html::displayNotFoundError();
}
+Session::checkCSRF();
+
if (isset($_POST['connect'])) {
if (!Profile::canCurrentUser(UPDATE) && !Profile::canCurrentUser(CREATE)) {
Html::displayRightError();
diff --git a/front/config.form.php b/front/config.form.php
index 5041d4e..50b3aae 100644
--- a/front/config.form.php
+++ b/front/config.form.php
@@ -3,7 +3,6 @@
declare(strict_types=1);
use GlpiPlugin\Urbackup\Config;
-use Html;
global $CFG_GLPI;
@@ -14,6 +13,7 @@ if (!Session::haveRight('config', UPDATE)) {
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update'])) {
+ Session::checkCSRF();
Config::saveConfiguration($_POST);
Html::redirect($_SERVER['REQUEST_URI']);
}
diff --git a/front/server.form.php b/front/server.form.php
index f812d15..7fdd0dd 100644
--- a/front/server.form.php
+++ b/front/server.form.php
@@ -19,6 +19,8 @@ if (!Profile::canCurrentUser(READ)) {
$server = new Server();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ Session::checkCSRF();
+
if (isset($_POST['link_asset'])) {
$itemtype = (string) ($_POST['itemtype'] ?? '');
$items_id = (int) ($_POST['items_id'] ?? 0);
diff --git a/front/server.php b/front/server.php
index d4fc148..e2a68c3 100644
--- a/front/server.php
+++ b/front/server.php
@@ -4,8 +4,6 @@ declare(strict_types=1);
use GlpiPlugin\Urbackup\Profile;
use GlpiPlugin\Urbackup\Server;
-use Html;
-use Search;
if (!defined('GLPI_ROOT')) {
define('GLPI_ROOT', dirname(__DIR__, 4));
diff --git a/front/server.test.php b/front/server.test.php
deleted file mode 100644
index 65790e7..0000000
--- a/front/server.test.php
+++ /dev/null
@@ -1,64 +0,0 @@
- false, 'message' => 'Unauthorized']);
- exit;
-}
-
-// Check rights
-if (!Session::haveRight('plugin_urbackup', READ)) {
- http_response_code(403);
- echo json_encode(['success' => false, 'message' => 'Forbidden - No right plugin_urbackup READ']);
- exit;
-}
-
-$server_id = (int) (($_GET['id'] ?? $_POST['id'] ?? 0));
-
-if ($server_id <= 0) {
- echo json_encode(['success' => false, 'message' => 'Invalid server ID']);
- exit;
-}
-
-// Load plugin classes
-$classes = ['Server', 'UrbackupApiClient'];
-foreach ($classes as $class) {
- $file = PLUGIN_URBACKUP_DIR . '/src/' . $class . '.php';
- if (file_exists($file)) {
- require_once $file;
- }
-}
-
-$server = new \GlpiPlugin\Urbackup\Server();
-
-if (!$server->getFromDB($server_id)) {
- echo json_encode(['success' => false, 'message' => 'Server not found']);
- exit;
-}
-
-try {
- $client = new \GlpiPlugin\Urbackup\UrbackupApiClient($server);
- $result = $client->testConnection();
-
- $server->update([
- 'id' => $server_id,
- 'last_api_status' => $result['success'] ? 1 : 0,
- 'last_api_message' => $result['message'],
- 'last_api_check' => date('Y-m-d H:i:s'),
- ]);
-
- echo json_encode($result);
-} catch (Throwable $e) {
- echo json_encode(['success' => false, 'message' => $e->getMessage()]);
-}
diff --git a/front/server.view.php b/front/server.view.php
deleted file mode 100644
index 90a894f..0000000
--- a/front/server.view.php
+++ /dev/null
@@ -1,42 +0,0 @@
-getFromDB($ID)) {
- Html::redirect(PLUGIN_URBACKUP_WEB_DIR . '/front/server.php');
-}
-
-Html::header(
- $server->fields['name'] . ' - UrBackup',
- '',
- 'Assets',
- 'GlpiPlugin\Urbackup\Server'
-);
-
-$server->display([
- 'id' => $ID,
- 'show_nav' => true,
- 'show_tabs' => true,
-]);
-
-Html::footer();
\ No newline at end of file
diff --git a/front/server_test.ajax.php b/front/server_test.ajax.php
index 79a7b97..8fc466a 100644
--- a/front/server_test.ajax.php
+++ b/front/server_test.ajax.php
@@ -13,6 +13,10 @@ Html::header_nocache();
Session::checkLoginUser();
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ Session::checkCSRF();
+}
+
if (!Session::haveRight('plugin_urbackup', READ)) {
echo json_encode(['success' => false, 'message' => __('No permission', 'urbackup')]);
exit;
diff --git a/front/test.button.php b/front/test.button.php
deleted file mode 100644
index 1718114..0000000
--- a/front/test.button.php
+++ /dev/null
@@ -1,43 +0,0 @@
-No READ permission on plugin_urbackup
";
- Html::footer();
- exit;
-}
-
-echo "READ permission OK
";
-
-// Get server ID
-$server_id = (int) ($_GET['id'] ?? 0);
-
-if ($server_id > 0) {
- $server = new GlpiPlugin\Urbackup\Server();
- if ($server->getFromDB($server_id)) {
- echo "Server: " . $server->fields['name'] . "
";
-
- $client = new GlpiPlugin\Urbackup\UrbackupApiClient($server);
- $result = $client->testConnection();
-
- echo "" . print_r($result, true) . "
";
- } else {
- echo "Server not found
";
- }
-} else {
- echo "No server ID provided
";
-}
-
-Html::footer();
diff --git a/install/install.php b/install/install.php
index 4473388..1f3d7c3 100644
--- a/install/install.php
+++ b/install/install.php
@@ -31,14 +31,15 @@ function plugin_urbackup_install_process(): bool
plugin_urbackup_install_create_initial_schema($migration);
plugin_urbackup_install_update_configs_table($migration);
- plugin_urbackup_install_update_assettypes_table($migration);
// Convert old assettype configurations to GLPI 11 capacity system
plugin_urbackup_install_convert_assettypes_to_capacities($migration);
plugin_urbackup_install_update_servers_table($migration);
plugin_urbackup_install_update_serverassets_table($migration);
- plugin_urbackup_install_update_profiles_table($migration);
+
+ // Drop tables that are no longer used (replaced by Profile::registerRights() and Capacity system)
+ plugin_urbackup_install_drop_legacy_tables($migration);
$migration->executeMigration();
@@ -61,10 +62,8 @@ function plugin_urbackup_install_create_initial_schema(Migration $migration): vo
$required_tables = [
'glpi_plugin_urbackup_configs',
- 'glpi_plugin_urbackup_assettypes',
'glpi_plugin_urbackup_servers',
'glpi_plugin_urbackup_serverassets',
- 'glpi_plugin_urbackup_profiles',
];
$missing_table_found = false;
@@ -264,6 +263,7 @@ function plugin_urbackup_install_update_servers_table(Migration $migration): voi
$migration->addKey($table, 'entities_id');
$migration->addKey($table, 'locations_id');
$migration->addKey($table, 'is_active');
+ $migration->addKey($table, ['locations_id', 'is_active'], 'location_active');
}
/**
@@ -298,46 +298,39 @@ function plugin_urbackup_install_update_serverassets_table(Migration $migration)
'after' => 'itemtype',
]);
+ $migration->addField($table, 'date_creation', 'timestamp');
+ $migration->addField($table, 'date_mod', 'timestamp');
+
$migration->addKey($table, 'plugin_urbackup_servers_id');
$migration->addKey($table, ['itemtype', 'items_id'], 'item');
}
/**
- * Update profiles table.
+ * Drop legacy tables that are no longer used.
*
* @param Migration $migration Migration instance
*
* @return void
*/
-function plugin_urbackup_install_update_profiles_table(Migration $migration): void
+function plugin_urbackup_install_drop_legacy_tables(Migration $migration): void
{
global $DB;
+ // glpi_plugin_urbackup_profiles was replaced by Profile::registerRights() in 0.5.0
$table = 'glpi_plugin_urbackup_profiles';
-
- if (!$DB->tableExists($table)) {
- return;
+ if ($DB->tableExists($table)) {
+ $migration->displayMessage(__('Dropping legacy glpi_plugin_urbackup_profiles table', 'urbackup'));
+ $DB->queryOrDie("DROP TABLE IF EXISTS `$table`");
}
- $migration->addField($table, 'profiles_id', 'integer', [
- 'value' => 0,
- 'after' => 'id',
- ]);
+ // glpi_plugin_urbackup_assettypes was replaced by GLPI 11 Capacity system in 0.6.0
+ $table2 = 'glpi_plugin_urbackup_assettypes';
+ if ($DB->tableExists($table2)) {
+ $migration->displayMessage(__('Dropping legacy glpi_plugin_urbackup_assettypes table', 'urbackup'));
+ $DB->queryOrDie("DROP TABLE IF EXISTS `$table2`");
+ }
- $migration->addField($table, 'rightname', 'string', [
- 'value' => '',
- 'after' => 'profiles_id',
- ]);
-
- $migration->addField($table, 'rights', 'integer', [
- 'value' => 0,
- 'after' => 'rightname',
- ]);
-
- $migration->addField($table, 'date_creation', 'timestamp');
- $migration->addField($table, 'date_mod', 'timestamp');
-
- $migration->addKey($table, ['profiles_id', 'rightname'], 'profile_right');
+ $migration->displayMessage(__('Legacy tables dropped successfully', 'urbackup'));
}
/**
diff --git a/install/mysql/plugin_urbackup-empty.sql b/install/mysql/plugin_urbackup-empty.sql
index 52e7a86..ff173f3 100644
--- a/install/mysql/plugin_urbackup-empty.sql
+++ b/install/mysql/plugin_urbackup-empty.sql
@@ -8,17 +8,6 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_urbackup_configs` (
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
-CREATE TABLE IF NOT EXISTS `glpi_plugin_urbackup_assettypes` (
- `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
- `itemtype` VARCHAR(255) NOT NULL DEFAULT '',
- `is_active` TINYINT NOT NULL DEFAULT 0,
- `date_creation` TIMESTAMP NULL DEFAULT NULL,
- `date_mod` TIMESTAMP NULL DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `itemtype` (`itemtype`),
- KEY `is_active` (`is_active`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
-
CREATE TABLE IF NOT EXISTS `glpi_plugin_urbackup_servers` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`entities_id` INT UNSIGNED NOT NULL DEFAULT 0,
@@ -43,7 +32,8 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_urbackup_servers` (
KEY `name` (`name`),
KEY `entities_id` (`entities_id`),
KEY `locations_id` (`locations_id`),
- KEY `is_active` (`is_active`)
+ KEY `is_active` (`is_active`),
+ KEY `location_active` (`locations_id`, `is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `glpi_plugin_urbackup_serverassets` (
@@ -51,18 +41,11 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_urbackup_serverassets` (
`plugin_urbackup_servers_id` INT UNSIGNED NOT NULL DEFAULT 0,
`itemtype` VARCHAR(255) NOT NULL DEFAULT '',
`items_id` INT UNSIGNED NOT NULL DEFAULT 0,
+ `date_creation` TIMESTAMP NULL DEFAULT NULL,
+ `date_mod` TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `plugin_urbackup_servers_id` (`plugin_urbackup_servers_id`),
KEY `item` (`itemtype`, `items_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
-CREATE TABLE IF NOT EXISTS `glpi_plugin_urbackup_profiles` (
- `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
- `profiles_id` INT UNSIGNED NOT NULL DEFAULT 0,
- `rightname` VARCHAR(255) NOT NULL DEFAULT '',
- `rights` INT NOT NULL DEFAULT 0,
- `date_creation` TIMESTAMP NULL DEFAULT NULL,
- `date_mod` TIMESTAMP NULL DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `profile_right` (`profiles_id`, `rightname`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
\ No newline at end of file
+-- glpi_plugin_urbackup_profiles was dropped in 0.7.0 (replaced by Profile::registerRights())
\ No newline at end of file
diff --git a/js/urbackup.js b/js/urbackup.js
deleted file mode 100644
index e4e4b51..0000000
--- a/js/urbackup.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * UrBackup API Test JavaScript
- */
-(function () {
- 'use strict';
-
- function testApi(serverId, resultBox) {
- if (!serverId || !resultBox) return;
-
- var xhr = new XMLHttpRequest();
- xhr.open('POST', '/plugins/urbackup/ajax/server_test.php', true);
- xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
- xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
- xhr.timeout = 8000;
-
- xhr.onload = function () {
- if (xhr.status === 200) {
- try {
- var data = JSON.parse(xhr.responseText);
- if (data.success) {
- resultBox.innerHTML = ' ' + 'API connection OK' + '';
- } else {
- var message = data.message || 'Connection failed';
- var isNetwork = /timeout|could not resolve|couldn't connect|connection refused|connection timed out|network is unreachable|no route to host|returned HTTP status/i.test(message);
- var statusClass = isNetwork ? 'text-warning' : 'text-danger';
- var icon = isNetwork ? 'ti-wifi-off' : 'ti-x';
- var label = isNetwork ? 'Server unreachable' : 'API connection failed';
- resultBox.innerHTML = ' ' + label + '
' + message + '';
- }
- } catch (e) {
- resultBox.innerHTML = ' Error';
- }
- } else {
- resultBox.innerHTML = ' HTTP ' + xhr.status + '';
- }
- };
-
- xhr.ontimeout = function () {
- resultBox.innerHTML = ' Server unreachable
Connection timeout';
- };
-
- xhr.onerror = function () {
- resultBox.innerHTML = ' Server unreachable
Network error';
- };
-
- xhr.send('id=' + encodeURIComponent(serverId));
- }
-
- function initApiStatusCheck() {
- var statusBox = document.getElementById('plugin-urbackup-api-status');
- if (!statusBox) return;
- if (statusBox._initialized) return;
- statusBox._initialized = true;
-
- var serverId = statusBox.getAttribute('data-server-id');
- if (serverId) {
- testApi(serverId, statusBox);
- }
- }
-
- function initApiTestButtons() {
- var buttons = document.querySelectorAll('.plugin-urbackup-test-api');
-
- buttons.forEach(function (button) {
- if (button._initialized) return;
- button._initialized = true;
-
- button.addEventListener('click', function (e) {
- e.preventDefault();
- e.stopPropagation();
-
- var serverId = button.getAttribute('data-server-id');
- var resultBox = document.getElementById('plugin-urbackup-api-test-result');
-
- testApi(serverId, resultBox);
- });
- });
- }
-
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', initApiStatusCheck);
- document.addEventListener('DOMContentLoaded', initApiTestButtons);
- } else {
- setTimeout(initApiStatusCheck, 100);
- setTimeout(initApiTestButtons, 100);
- }
-})();
diff --git a/remove_deprecated_files.sh b/remove_deprecated_files.sh
deleted file mode 100755
index b145d5c..0000000
--- a/remove_deprecated_files.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# Remove deprecated front/ and ajax/ files for GLPI 11 compliance
-echo "Removing deprecated front/ and ajax/ files..."
-rm -f /var/www/glpi/plugins/urbackup/front/config.form.php
-rm -f /var/www/glpi/plugins/urbackup/front/server.php
-rm -f /var/www/glpi/plugins/urbackup/front/server.form.php
-rm -f /var/www/glpi/plugins/urbackup/front/asset.form.php
-rm -f /var/www/glpi/plugins/urbackup/ajax/server_test.php
-rm -f /var/www/glpi/plugins/urbackup/ajax/server_clients.php
-rm -f /var/www/glpi/plugins/urbackup/ajax/asset_action.php
-echo "Files removed. Note: The plugin now uses Symfony Controllers."
diff --git a/removed/profile.form.php___ b/removed/profile.form.php___
deleted file mode 100644
index 6ed0ada..0000000
--- a/removed/profile.form.php___
+++ /dev/null
@@ -1,41 +0,0 @@
-setName('urbackup:test-api')
- ->setDescription('Test UrBackup server API connection')
- ->addArgument('server_id', InputArgument::REQUIRED, 'Server ID');
- }
-
- protected function execute(InputInterface $input, OutputInterface $output): int
- {
- $server_id = (int) $input->getArgument('server_id');
-
- $server = new Server();
- if (!$server->getFromDB($server_id)) {
- $output->writeln("Server not found: $server_id");
- return Command::FAILURE;
- }
-
- $output->writeln("Testing API for: " . $server->fields['name']);
- $output->writeln("URL: " . $server->getWebInterfaceUrl());
- $output->writeln("Username: " . $server->fields['api_username']);
-
- $client = new UrbackupApiClient($server);
-
- try {
- $result = $client->testConnection();
-
- if ($result['success']) {
- $output->writeln("SUCCESS: " . $result['message'] . "");
- $output->writeln("Identity: " . $result['identity']);
- } else {
- $output->writeln("FAILED: " . $result['message'] . "");
- }
-
- return $result['success'] ? Command::SUCCESS : Command::FAILURE;
- } catch (\Throwable $e) {
- $output->writeln("Exception: " . $e->getMessage() . "");
- return Command::FAILURE;
- }
- }
-}
diff --git a/src/Controller/AssetController.php b/src/Controller/AssetController.php
deleted file mode 100644
index 45eb9b7..0000000
--- a/src/Controller/AssetController.php
+++ /dev/null
@@ -1,191 +0,0 @@
-request->get('itemtype', '');
- $items_id = (int) $request->request->get('items_id', 0);
-
- if ($itemtype === '' || $items_id <= 0 || !class_exists($itemtype)) {
- Session::addMessageAfterRedirect(
- __('Invalid asset reference.', 'urbackup'),
- true,
- ERROR
- );
- Html::back();
- }
-
- if (!Config::isItemtypeEnabled($itemtype)) {
- Session::addMessageAfterRedirect(
- __('UrBackup is not enabled for this asset type.', 'urbackup'),
- true,
- ERROR
- );
- Html::back();
- }
-
- $item = new $itemtype();
-
- if (!$item instanceof CommonDBTM || !$item->getFromDB($items_id)) {
- Session::addMessageAfterRedirect(
- __('Asset not found.', 'urbackup'),
- true,
- ERROR
- );
- Html::back();
- }
-
- $action = (string) $request->request->get('urbackup_action', '');
-
- switch ($action) {
- case 'connect':
- $server_id = (int) $request->request->get('plugin_urbackup_servers_id', 0);
- if (ServerAsset::connectAssetToServer($itemtype, $items_id, $server_id)) {
- Session::addMessageAfterRedirect(
- __('Asset connected to UrBackup server.', 'urbackup'),
- true,
- INFO
- );
- }
- break;
-
- case 'disconnect':
- if (ServerAsset::disconnectAsset($itemtype, $items_id)) {
- Session::addMessageAfterRedirect(
- __('Asset disconnected from UrBackup server.', 'urbackup'),
- true,
- INFO
- );
- }
- break;
-
- case 'set_internet_mode':
- if (Profile::canCurrentUser(UPDATE)) {
- $enabled = (int) $request->request->get('internet_mode', 0) === 1;
- $link = ServerAsset::getLinkForAsset($itemtype, $items_id, true);
- if ($link) {
- $server = new Server();
- if ($server->getFromDB((int) $link['plugin_urbackup_servers_id'])) {
- $api = new UrbackupApiClient($server);
- $client_name = (string) ($item->fields['name'] ?? '');
- $api->saveInternetMode($client_name, $enabled);
- }
- }
- }
- break;
-
- case 'create_client':
- if (Profile::canCurrentUser(CREATE)) {
- $serverAsset = new ServerAsset();
- $link = ServerAsset::getLinkForAsset($itemtype, $items_id, true);
- if ($link) {
- $server = new Server();
- if ($server->getFromDB((int) $link['plugin_urbackup_servers_id'])) {
- $api = new UrbackupApiClient($server);
- $client_name = (string) ($item->fields['name'] ?? '');
- $api->addClient($client_name);
- }
- }
- }
- break;
-
- case 'incremental_file_backup':
- case 'full_file_backup':
- case 'incremental_image_backup':
- case 'full_image_backup':
- if (Profile::canCurrentUser(UPDATE)) {
- $serverAsset = new ServerAsset();
- $link = ServerAsset::getLinkForAsset($itemtype, $items_id, true);
- if ($link) {
- $server = new Server();
- if ($server->getFromDB((int) $link['plugin_urbackup_servers_id'])) {
- $api = new UrbackupApiClient($server);
- $client_name = (string) ($item->fields['name'] ?? '');
- switch ($action) {
- case 'incremental_file_backup':
- $api->startIncrementalFileBackup($client_name);
- break;
- case 'full_file_backup':
- $api->startFullFileBackup($client_name);
- break;
- case 'incremental_image_backup':
- $api->startIncrementalImageBackup($client_name);
- break;
- case 'full_image_backup':
- $api->startFullImageBackup($client_name);
- break;
- }
- }
- }
- }
- break;
-
- case 'delete_client':
- if (Profile::canCurrentUser(PURGE)) {
- $serverAsset = new ServerAsset();
- $link = ServerAsset::getLinkForAsset($itemtype, $items_id, true);
- if ($link) {
- $server = new Server();
- if ($server->getFromDB((int) $link['plugin_urbackup_servers_id'])) {
- $api = new UrbackupApiClient($server);
- $client_name = (string) ($item->fields['name'] ?? '');
- $api->removeClient($client_name);
- }
- }
- }
- break;
- }
-
- Html::back();
- }
-
- #[Route('/plugin/urbackup/api/clients', name: 'urbackup_api_clients', methods: ['GET'])]
- public function getClients(Request $request): JsonResponse
- {
- Session::checkLoginUser();
-
- $server_id = (int) $request->query->get('server_id', 0);
-
- if ($server_id <= 0) {
- return new JsonResponse([]);
- }
-
- $server = new Server();
-
- if (!$server->getFromDB($server_id)) {
- return new JsonResponse([]);
- }
-
- $api = new UrbackupApiClient($server);
- $clients = $api->getStatus();
-
- return new JsonResponse($clients);
- }
-}
diff --git a/src/Controller/ConfigController.php b/src/Controller/ConfigController.php
deleted file mode 100644
index 1db03e4..0000000
--- a/src/Controller/ConfigController.php
+++ /dev/null
@@ -1,36 +0,0 @@
-isMethod('POST') && $request->request->has('update')) {
- Config::saveConfiguration($request->request->all());
- Html::back();
- }
-
- return $this->render('config/config.html.twig', []);
- }
-}
diff --git a/src/Controller/ServerController.php b/src/Controller/ServerController.php
deleted file mode 100644
index 63ea5c4..0000000
--- a/src/Controller/ServerController.php
+++ /dev/null
@@ -1,109 +0,0 @@
- '\d+'])]
- public function showServer(int $id): void
- {
- $server = new Server();
-
- if ($id > 0) {
- $server->check($id, READ);
- } else {
- $server->check(-1, CREATE);
- $server->getEmpty();
- }
-
- $server->display(['id' => $id]);
- }
-
- #[Route('/plugin/urbackup/server/test/{id}', name: 'urbackup_server_test', methods: ['POST', 'GET'])]
- public function testConnection(int $id = 0): JsonResponse
- {
- if (!Profile::canCurrentUser(READ)) {
- return new JsonResponse([
- 'success' => false,
- 'message' => 'No permission',
- ], 403);
- }
-
- if ($id <= 0) {
- $id = (int) ($_POST['id'] ?? $_GET['id'] ?? 0);
- }
-
- if ($id <= 0) {
- return new JsonResponse([
- 'success' => false,
- 'message' => 'Invalid server ID',
- ], 400);
- }
-
- $server = new Server();
-
- if (!$server->getFromDB($id)) {
- return new JsonResponse([
- 'success' => false,
- 'message' => 'Server not found',
- ], 404);
- }
-
- try {
- $client = new UrbackupApiClient($server);
- $result = $client->testConnection();
-
- $server->update([
- 'id' => $id,
- 'last_api_status' => $result['success'] ? 1 : 0,
- 'last_api_message' => $result['message'],
- 'last_api_check' => date('Y-m-d H:i:s'),
- ]);
-
- return new JsonResponse($result);
- } catch (Throwable $e) {
- return new JsonResponse([
- 'success' => false,
- 'message' => $e->getMessage(),
- ], 500);
- }
- }
-}
diff --git a/templates/asset/asset_tab.html.twig b/templates/asset/asset_tab.html.twig
deleted file mode 100644
index 909971e..0000000
--- a/templates/asset/asset_tab.html.twig
+++ /dev/null
@@ -1,69 +0,0 @@
-
- {% if not linked %}
-
- {{ __('No UrBackup server linked.', 'urbackup') }}
-
-
-
- | {{ __('UrBackup server selection', 'urbackup') }} |
-
- {% if is_sub_location %}
-
- |
- {{ __('The asset is in a sub-location. The plugin will use the server assigned to the root location.', 'urbackup') }}
- |
-
- {% endif %}
- {% if servers|length == 0 %}
-
- |
-
- {{ __('No UrBackup server available for the root location of this asset.', 'urbackup') }}
-
- |
-
- {% elseif can_connect %}
-
- | {{ __('Available servers for root location', 'urbackup') }} |
-
-
- |
-
- {% else %}
-
- |
- {{ __('A server is available, but you do not have permission to link this asset.', 'urbackup') }}
- |
-
- {% endif %}
-
- {% else %}
-
-
- | {{ __('UrBackup status', 'urbackup') }} |
-
-
- | {{ __('Linked server', 'urbackup') }} |
- {{ server_link }} |
- {{ __('IP address', 'urbackup') }} |
- {{ server_ip }} |
-
-
- | {{ __('UrBackup server version', 'urbackup') }} |
- {{ server_version }} |
- {{ __('Client name', 'urbackup') }} |
- {{ client_name }} |
-
-
- {% endif %}
-
diff --git a/templates/config/config.html.twig b/templates/config/config.html.twig
deleted file mode 100644
index 1c3bb16..0000000
--- a/templates/config/config.html.twig
+++ /dev/null
@@ -1,18 +0,0 @@
-
diff --git a/templates/server/server_form.html.twig b/templates/server/server_form.html.twig
deleted file mode 100644
index 14e1027..0000000
--- a/templates/server/server_form.html.twig
+++ /dev/null
@@ -1,118 +0,0 @@
-{% extends 'layout.html.twig' %}
-
-{% block content %}
-
-{% endblock %}
diff --git a/templates/server/server_list.html.twig b/templates/server/server_list.html.twig
deleted file mode 100644
index f00e847..0000000
--- a/templates/server/server_list.html.twig
+++ /dev/null
@@ -1,51 +0,0 @@
-{% extends 'layout.html.twig' %}
-
-{% block content %}
-
-
-
- | {{ __('UrBackup servers', 'urbackup') }} |
-
-
- | {{ __('Name') }} |
- {{ __('IP address', 'urbackup') }} |
- {{ __('Port') }} |
- {{ __('Version') }} |
- {{ __('Status') }} |
- {{ __('Actions') }} |
-
- {% for server in servers %}
-
- | {{ server.name }} |
- {{ server.ip_address }} |
- {{ server.port }} |
- {{ server.server_version }} |
-
- {% if server.last_api_status %}
- {{ __('OK', 'urbackup') }}
- {% else %}
- {{ __('Failed', 'urbackup') }}
- {% endif %}
- |
-
-
- {{ __('View') }}
-
-
- |
-
- {% else %}
-
- | {{ __('No records found', 'urbackup') }} |
-
- {% endfor %}
-
- {% if can_create %}
-
- {{ __('Add') }}
-
- {% endif %}
-
-{% endblock %}