gestione assets

This commit is contained in:
mariano
2026-05-22 08:29:59 +02:00
parent f7c1ab8aa4
commit 13cb325576
11 changed files with 391 additions and 627 deletions
+167 -271
View File
@@ -1,179 +1,160 @@
# UrBackup Plugin - Memoria di Sviluppo
## 📋 Informazioni Plugin
## Informazioni Plugin
- **Nome**: UrBackup
- **Versione**: 0.4.2
- **Versione**: 0.5.0
- **Compatibilità**: GLPI 11.0.6+, PHP 8.3+
- **Namespace**: `GlpiPlugin\Urbackup`
## ✅ Funzionalità Implementate
## Struttura File
```
plugin_urbackup/
├── setup.php # Hook init, menu, tab, versione, prerequisiti
├── hook.php # Install/uninstall, massive actions, class list
├── composer.json # PSR-4 autoloading
├── src/
│ ├── Config.php # Configurazione plugin (Computer sempre attivo, capacità)
│ ├── Profile.php # Diritti utente
│ ├── Server.php # CRUD server UrBackup
│ ├── ServerAsset.php # Linking asset-server
│ ├── AssetTab.php # Tab UrBackup su asset GLPI
│ ├── MassiveAction.php # Azioni massive connect/disconnect
│ ├── UrbackupApiClient.php # Client API UrBackup
│ ├── LocationHelper.php # Helper assegnazione server per location
│ ├── Capacity/
│ │ └── UrBackupCapacity.php # Capacity per Asset Definition GLPI 11
│ ├── Controller/
│ │ ├── ServerController.php
│ │ ├── AssetController.php
│ │ └── ConfigController.php
│ └── Command/
│ └── TestApiCommand.php
├── install/
│ ├── install.php # Schema DB, migrazioni, capacity migration
│ ├── uninstall.php # Drop tabelle, pulizia diritti
│ └── mysql/
│ └── plugin_urbackup-empty.sql # Schema iniziale
├── front/
│ ├── config.form.php # Config plugin (Computer info)
│ ├── server.php # Lista server
│ ├── server.form.php # Form server con tab laterali
│ └── asset.form.php # Azioni asset (connect/disconnect/backup)
├── ajax/
│ └── server_test.php # Test connessione API
├── templates/
│ └── config/
│ └── config.html.twig # Config page Twig
├── locales/ # Traduzioni (it, en, de)
├── css/ & js/ # Asset frontend
└── MEMORY.md # Questo file
```
### Installazione/Disinstallazione
- ✅ Installazione plugin tramite CLI: `php bin/console glpi:plugin:install urbackup`
- ✅ Attivazione: `php bin/console glpi:plugin:activate urbackup`
- ✅ Disinstallazione: `php bin/console glpi:plugin:uninstall urbackup`
### Struttura File
- `setup.php`: Hook di inizializzazione, menu, tab, versione, prerequisiti
- `hook.php`: Funzioni di installazione (spostate in setup.php per OPcache)
- `src/`: Classi namespaced con namespace `GlpiPlugin\Urbackup`
- `install/`: Script di installazione e disinstallazione database
- `front/`: Pagine PHP per lista server e form
- `ajax/`: Endpoint AJAX per test API (`server_test.php`)
### Classi Principali
## Classi Principali
| Classe | Descrizione |
|--------|-------------|
| `Config` | Configurazione plugin, tipi asset abilitati |
| `Config` | Configurazione plugin, isItemtypeEnabled |
| `Profile` | Diritti utente, permessi |
| `Server` | Server UrBackup (CRUD) |
| `Server` | CRUD server UrBackup |
| `ServerAsset` | Linking asset-server |
| `AssetTab` | Tab visualizzato sugli asset |
| `MassiveAction` | Azioni massive |
| `UrbackupApiClient` | Client API per comunicazione con UrBackup server |
| `LocationHelper` | Helper per assegnazione server basata su location |
| `Controller/ServerController` | Symfony controller per routes server |
| `Controller/AssetController` | Symfony controller per azioni asset |
| `Command/TestApiCommand` | CLI command per test API |
| `AssetTab` | Tab UrBackup su asset |
| `MassiveAction` | Azioni massive connect/disconnect |
| `UrbackupApiClient` | Client API UrBackup (PBKDF2 auth) |
| `LocationHelper` | Assegnazione server per location |
| `Capacity/UrBackupCapacity` | Capacity per Asset Definition (cleanup + tracking) |
| `Controller/ServerController` | Route Symfony per server |
| `Controller/AssetController` | Route Symfony per azioni asset |
| `Command/TestApiCommand` | CLI test API |
### Pagine Frontend
- `front/config.form.php`: Pagina configurazione plugin
- `front/server.php`: Lista server UrBackup
- `front/server.form.php`: Form aggiunta/modifica server
- `front/asset.form.php`: Form azioni su asset (connect/disconnect/start backup)
- `ajax/server_test.php`: Endpoint AJAX per test connessione API
## Interfacce GLPI
- Menu: Amministrazione → Server UrBackup
- Tab UrBackup su Computer (sempre) + tutti gli Asset Definition
- Config: Computer sempre attivo; Asset Definition gestiti via native Capacities UI
### Interfacce GLPI
- ✅ Menu: Amministrazione → Server UrBackup
- ✅ Tab: UrBackup su Computer e asset abilitati
- ✅ Configurazione: Abilitazione tipi asset (legacy + Asset Definition GLPI 11)
## Architettura Capacities (v0.5.0)
## 🔧 Fix e Correzioni Applicate
### Flusso
```
Kernel boot: PostBootEvent
├── (110) InitializePlugins → plugin_init_urbackup()
│ ├── Plugin::registerClass(AssetTab, ['Computer']) ← Computer legacy
│ └── AssetDefinitionManager::registerCapacity() ← UrBackupCapacity registrata
├── (100) CustomObjectsBoot → bootDefinitions()
│ └── foreach definition con UrBackupCapacity abilitata:
│ └── UrBackupCapacity::onClassBootstrap($classname)
│ └── CommonGLPI::registerStandardTab($classname, AssetTab::class)
│ ↑ Tab registrato QUI, dopo che le definizioni sono caricate dal DB
Config::isItemtypeEnabled($itemtype)
├── '' → false
├── 'Computer' → true
├── Asset subclass → true ← SEMPRE visibile
└── altro → false
UrBackupCapacity
├── onClassBootstrap() → registra AssetTab sul definition classname
├── onCapacityDisabled() → pulisce ServerAsset entries
├── isUsed() / getCapacityUsageDescription() → UI Capacities
```
1. **OPcache**: Funzioni install in setup.php (non in hook.php) per problema OPcache
2. **Duplicate profilerights**: Aggiunto check in `Profile::registerRights()` per evitare duplicati
3. **CSRF**: Include `inc/includes.php` nei file front per gestione CSRF
4. **Firme metodi**: Corretto `getTabNameForItem(CommonGLPI, int)` e `displayTabContentForItem(CommonGLPI, int, int)`
5. **AssetTab incompleto**: Completato metodo `formatTimestamp()` mancante
6. **RIGHT_NAME costante inesistente**: Sostituito `Profile::RIGHT_NAME` con stringa `'plugin_urbackup'` in AssetTab, ServerAsset e MassiveAction. La costante non esiste nel plugin, era un errore di copia-incolla.
7. **Profile self-reference**: Corretto `displayTabContentForItem()` per usare `\Profile` (core GLPI) invece di `Profile` (plugin)
8. **UrbackupApiClient riscritto completamente**: Basato sul Python wrapper, con le seguenti correzioni chiave:
- Session passata sia nell'URL che nel body POST
- Content-Type: `application/x-www-form-urlencoded; charset=UTF-8`
- Autenticazione PBKDF2 compatibile con server UrBackup
- Login flow: anonymous → salt → login con hash
- Gestione errore `{"error": 1}` per username inesistente
9. **`htmlescape()` non esistente**: Sostituito con `htmlspecialchars()` in tutti i file (AssetTab, Server, ServerAsset, MassiveAction, Config). La funzione `htmlescape()` non è definita in GLPI né in PHP.
10. **File `front/asset.form.php` mancante**: Creato per gestire connect/disconnect/start_backup dal tab asset.
11. **File debug/junk rimossi**: Eliminati debug_session.php, hook_corrected.php, rector.php, KILL_VED.php, front/debug.php.
12. **`initProfile()` obbligatorio**: Reso `$profile` nullable (`$profile = null`) per compatibilità con GLPI che chiama `initProfile()` senza argomenti.
### Separazione responsabilità
- **Registrazione tab**: `UrBackupCapacity::onClassBootstrap()` — chiamata da `bootDefinitions()` per ogni definizione con capacità abilitata
- **Visibilità tab**: `Config::isItemtypeEnabled()` — sempre true per Asset subclasses
- **Pulizia**: `UrBackupCapacity::onCapacityDisabled()` — quando admin disabilita la capacità
- **Config**: Computer sempre attivo; Capacities gestite dalla UI nativa GLPI
### Modifica Test API Connection (v0.4.3)
### Bug risolto: tab non registrato su Asset Definition nuovi
- **Causa**: `setup.php` iterava `getDefinitions()` durante `plugin_init_urbackup()`, ma `bootDefinitions()` (che carica le definizioni dal DB) gira DOPO (priority 100 vs 110), quindi `getDefinitions()` tornava sempre array vuoto
- **Fix**: La registrazione del tab è stata spostata in `UrBackupCapacity::onClassBootstrap()`, chiamata da `bootstrapDefinition()` durante `bootDefinitions()`, quando le definizioni sono già caricate e la classe dinamica è disponibile
- **Rimosso**: loop `foreach ($defs ...)` e debug logging da `setup.php`
- **Rimosso**: debug logging da `AssetTab.php`
**Data**: 2026-05-19
## Tabella glpi_plugin_urbackup_assettypes
- Colonna `is_default` rimossa (non serve più con capacities)
- Tabella vestigiale — non più usata per la logica applicativa
- Migrazione: `plugin_urbackup_install_convert_assettypes_to_capacities()` abilita capacità su tutte le definizioni
**Descrizione**: Modificato il comportamento del test API nel form del server:
- Rimosso il pulsante "Test API Connection" manuale
- Rimosse le righe "Last API status", "Last API message", "Last API check"
- Aggiunto controllo automatico della connessione API eseguito ad ogni visualizzazione del form
## Comandi Utili
```bash
# Installare il plugin
php bin/console glpi:plugin:install urbackup
**Stati visualizzati**:
- 🟢 **Verde** "Connessione API OK" - Connessione riuscita
- 🔴 **Rosso** "Connessione API fallita" - Errore di autenticazione o configurazione
- 🟡 **Giallo** "Server irraggiungibile" - Problemi di rete (timeout, DNS, HTTP 4xx/5xx, SSL)
# Attivare
php bin/console glpi:plugin:activate urbackup
**File modificati**:
- `src/Server.php`: Rimossa sezione pulsante e aggiunto metodo `testApiConnection()`
- `locales/it_IT.po`, `locales/en_GB.po`, `locales/de_DE.po`: Aggiunte traduzioni
# Disinstallare
echo "yes" | php bin/console glpi:plugin:uninstall urbackup
### API UrBackup - Endpoints Verificati
| Endpoint | Metodo | Note |
|----------|--------|------|
| `/x?a=login` | POST | Login anonimo o con sessione |
| `/x?a=salt&username=X` | POST | Richiede salt, ritorna ses + rnd |
| `/x?a=login` | POST | Con username, password hash, ses |
| `/x?a=status` | POST | Richiede ses nel body (non solo URL) |
## 📝 Checklist Pre-Consegna
# Verificare syntax PHP
php -l plugins/urbackup/src/*.php plugins/urbackup/front/*.php plugins/urbackup/*.php
```
## Checklist Pre-Consegna
- [x] `declare(strict_types=1);` in ogni file PHP
- [x] Namespace `Plugin\<Nome>\` e PSR-4 corretto
- [x] Namespace `GlpiPlugin\Urbackup\` e PSR-4 corretto
- [x] Check versione GLPI 11.0.6+ in `setup.php`
- [x] CSRF e permessi su ogni POST/AJAX
- [x] Query parametrizzate o `$DB->request()`
- [x] Output escaped e loggato
- [x] Nessun uso di API deprecate GLPI 11
- [x] Compatibilità PHP 8.3 verificata
- [ ] Istruzioni installazione e test incluse (da completare)
## 🚧 Da Completare
## Da Completare
1. Test funzionalità lista server e form
2. AJAX endpoint comunicazione API
1. **Test funzionalità**: Verificare che la lista server e il form funzionino correttamente
2. **Asset Definition**: Testare con Asset Definition di GLPI 11 se presenti
3. **AJAX**: Endpoint per comunicazione API con server UrBackup
4. **Logging**: Aggiungere trace per debugging
5. **composer.json**: Creare file con PSR-4 e dipendenze
### Verifiche Post-Migrazione Capacity
- [x] Tab UrBackup appare su Asset Definition nuovo (Computer + Asset)
- [ ] Upgrade da v0.4.x converte righe attive
- [ ] Colonna `is_default` droppata
- [ ] Disabilitazione capacità pulisce ServerAsset (onCapacityDisabled)
## 📌 Comandi Utili
```bash
# Installare il plugin
php bin/console glpi:plugin:install urbackup
# Attivare il plugin
php bin/console glpi:plugin:activate urbackup
# Disinstallare il plugin
echo "yes" | php bin/console glpi:plugin:uninstall urbackup
# Verificare syntax PHP
php -l plugins/urbackup/src/*.php
php -l plugins/urbackup/front/*.php
```
## 📚 Riferimenti
- GLPI 11 Plugin Development: https://glpi-project.org/documentation/
- Plugin Example: https://github.com/pluginsGLPI/example
- GLPI Inventory: https://github.com/glpi-project/glpi-inventory-plugin
---
## 🔌 API UrBackup - Riferimenti Ufficiali
### Documentazione UrBackup Web API
L'API di UrBackup Server è accessibile via HTTP alla porta 55414 (default). Gli endpoint sono accessibili tramite il path `/x` (es. `http://localhost:55414/x`).
### Risorse API Utilizzate
1. **Python Wrapper** (uroni/urbackup-server-python-web-api-wrapper)
- URL: https://github.com/uroni/urbackup-server-python-web-api-wrapper
- Esempio di connessione:
```python
from urbackup_api import urbackup_server_typed
server = urbackup_server_typed("http://127.0.0.1:55414/x", "admin", "password")
server.login()
```
2. **Node.js Wrapper** (bartmichu/node-urbackup-server-api)
- URL: https://github.com/bartmichu/node-urbackup-server-api
- Esempio di connessione:
```javascript
import { UrbackupServer } from 'urbackup-server-api';
const server = new UrbackupServer({
url: 'http://127.0.0.1:55414',
username: 'admin',
password: 'secretpassword',
});
```
### Endpoint API Principali
## API UrBackup - Riferimenti
### Endpoint API
| Metodo | Descrizione |
|--------|-------------|
| `login` | Autenticazione con username/password |
| `login` | Autenticazione username/password |
| `get_status` | Lista client con stato backup |
| `get_backups` | Lista backup per client |
| `start_backup` | Avvia backup (file/image) |
@@ -181,142 +162,57 @@ L'API di UrBackup Server è accessibile via HTTP alla porta 55414 (default). Gli
| `get_clients` | Lista clienti |
| `get_groups` | Lista gruppi |
### Implementazione Corrente
La classe `UrbackupApiClient` in `src/UrbackupApiClient.php` gestisce la connessione API. Il test di connessione deve:
1. Tentare login con credenziali salvate
2. Verificare risposta JSON valida
3. Mostrare messaggio di successo/errore
### Problemi Noti
- JSON Parse Error: API restituisce HTML invece di JSON con credenziali errate
- Timeout: Verificare raggiungibilità server UrBackup
- SSL: Se `ignore_ssl` attivo, accettare certificati self-signed
- AJAX 403: Funziona solo da browser con sessione GLPI attiva
- **JSON Parse Error**: L'API restituisce HTML invece di JSON quando le credenziali sono errate
- **Timeout**: Verificare che il server UrBackup sia raggiungibile
- **SSL**: Se `ignore_ssl` è attivo, accettare certificati auto-signati
### Debug - AJAX Endpoint 403 Error
## Cronologia Modifiche
Il test del pulsante "Test API" continua a restituire 403 Forbidden quando accesso via curl. Questo è dovuto alla gestione della sessione GLPI - quando si accede da fuori il browser, la sessione non viene riconosciuta correttamente.
### v0.4.2 — Refactoring server.form.php e tab laterali
- Side tabs a sinistra con nav-pills
- 4 tab: Server, Linked, Unlinked, Missing clients
- Missing clients con search/sort, location/AIP/group/state
- Navigazione server sopra i tab, indipendente
- Breadcrumb admin
- Fix namespace `getCachedName()`, Gruppo da `glpi_groups_items`
- Permessi: READ per accesso form, Connect/API nascosti per READ
- i18n: 17 stringhe nuove (it, en, de)
- Bug fix: ServerAsset colonne, asset.form.php disconnectAsset(), strict_types in 11 file
**Soluzione**: Il codice funziona quando accesso dal browser con sessione GLPI attiva. L'endpoint `front/server_test.ajax.php` e il JS in `public/js/urbackup.js` sono configurati correttamente.
### v0.4.6 — Funzionalità API completate
- Salvataggio Internet Mode su server UrBackup
- Salvataggio Default Dirs
- Backup file (incremental/full)
- Backup immagine (incremental/full)
- Recupero version client da API
**File chiave**:
- `front/server_test.ajax.php` - endpoint AJAX per test API
- `public/js/urbackup.js` - JavaScript per gestire il click del pulsante
### v0.4.5 — Tabella semplificata serverassets
- Rimossi campi: client_name, client_ip, client_version, is_active, last_file_backup, last_image_backup, last_sync, date_creation, date_mod, urbackup_client_id
- Solo: id, plugin_urbackup_servers_id, itemtype, items_id
**Test da effettuare**:
1. Accedere a GLPI con browser
2. Navigare a: Server UrBackup > Modifica server
3. Cliccare "Test API connection"
4. Verificare che appaia "Testing..." e poi il risultato
### v0.4.4 — Tab Linked/Unlinked Clients
- Dati da API UrBackup invece che da DB
- Nome tabella corretto: `glpi_plugin_urbackup_serverassets`
- Campo: `plugin_urbackup_servers_id`
### Modifica Tab Linked/Unlinked Clients (v0.4.4)
### v0.4.3 — Test API Connection automatico
- Rimosso pulsante manuale
- Rimosse righe last status/message/check
- Stati: verde OK, rosso fallito, giallo irraggiungibile
**Data**: 2026-05-19
### v0.5.0 — Capacity System per Asset Definition GLPI 11
- Rimpiazzata tabella custom `glpi_plugin_urbackup_assettypes` con Capacities native
- Computer: legacy (sempre attivo, fuori capacities)
- Asset Definition: tab sempre registrato, capacità gestisce cleanup
- `isItemtypeEnabled()` = true per tutti gli Asset
- `onClassBootstrap()` rimosso (poi reintrodotto in v0.5.1)
- File: `src/Capacity/UrBackupCapacity.php`
- Migration: auto-enable capacità su tutte le definizioni + drop is_default
**Descrizione**: Modificato il comportamento delle tabelle nel form del server:
**Linked Clients**:
- Query alla tabella `glpi_plugin_urbackup_serverassets` dove `plugin_urbackup_servers_id` = ID server
- Per ogni asset collegato: mostrare `client_name` (dal DB)
- Recuperare le altre info (status, last backup, IP) via API da UrBackup
- I campi statici nel DB (client_version, last_file_backup, last_image_backup, last_sync) non vengono più usati per la visualizzazione
**Unlinked Clients**:
- Chiamata API a UrBackup per ottenere tutti i client presenti sul server
- Escludere tutti i client che sono già nella tabella `glpi_plugin_urbackup_serverassets` (collegati a qualsiasi server, non solo quello visualizzato)
- Mostrare i client rimanenti con le info da API
**Correzione bug**:
- Nome tabella corretto: `glpi_plugin_urbackup_serverassets` (non `glpi_plugin_urbackup_server_assets`)
- Campo corretto: `plugin_urbackup_servers_id` (non `servers_id`)
**File modificati**:
- `src/Server.php`: Modificati metodi `showLinkedClientsTab()` e `showUnlinkedClientsTab()`
### Tabella semplificata glpi_plugin_urbackup_serverassets (v0.4.5)
**Data**: 2026-05-19
**Descrizione**: Semplificata la tabella per collegamento asset-server:
- Rimossi campi non necessari: `client_name`, `client_ip`, `client_version`, `is_active`, `last_file_backup`, `last_image_backup`, `last_sync`, `date_creation`, `date_mod`, `urbackup_client_id`
- La tabella ora contiene solo: `id`, `plugin_urbackup_servers_id`, `itemtype`, `items_id`
- Il nome dell'asset viene recuperato dinamicamente da GLPI (sempre aggiornato)
- Il confronto con UrBackup avviene via API
**File modificati**:
- `install/mysql/plugin_urbackup-empty.sql`: Schema semplificato
- `install/install.php`: Funzione aggiornata
- `src/ServerAsset.php`: Metodi `createForAsset()`, `getAssetName()`
- `src/AssetTab.php`: Recupero nome asset da GLPI
- `src/Server.php`: Tabelle Linked/Unlinked aggiornate
- `src/MassiveAction.php`: Rimossi messaggi confusing
- `front/asset.form.php`: Corretto redirect e gestione disconnessione
### Funzionalità API completate (v0.4.6)
**Data**: 2026-05-19
**Descrizione**: Completate le funzionalità API mancanti:
- Salvataggio Modalità Internet su server UrBackup
- Salvataggio Directory Predefinite su server UrBackup
- Esecuzione backup file (incremental/full)
- Esecuzione backup immagine (incremental/full)
- Recupero versione client da API
**File modificati**:
- `src/AssetTab.php`: Aggiunti metodi `startBackup()`, `saveInternetMode()`, `saveDefaultDirs()`
- `src/UrbackupApiClient.php`: Aggiunti metodi `updateClientSettings()`, `saveInternetMode()`
- `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
### v0.5.1 — Fix registrazione tab su Asset Definition nuovi
- **Bug**: Tab UrBackup non appariva su Asset Definition nuovi (es. `testnas`)
- **Causa**: `getDefinitions()` tornava 0 in `plugin_init_urbackup()` perché `bootDefinitions()` gira dopo (priority 100 vs 110)
- **Fix**: Spostata registrazione tab in `UrBackupCapacity::onClassBootstrap()` — chiamata durante `bootDefinitions()` per ogni definizione con capacità abilitata
- Rimossi debug logging superflui da `setup.php` e `AssetTab.php`