gestione documentale avanzata 1 parte

This commit is contained in:
2026-05-28 09:34:28 +02:00
parent 3471befb1a
commit f2b0833b90
34482 changed files with 4312269 additions and 546 deletions
+147 -1
View File
@@ -721,7 +721,22 @@ php artisan route:list --name=email
- `app/Http/Controllers/Admin/EmailSettingsController.php`: senderDestroy() con expectsJson()
- `resources/views/layouts/adminlte.blade.php`: rimossa voce Impostazioni Email dal sidebar
(Last updated: 27 Maggio 2026 - Password reset, profile, report enhancements)
(Last updated: 28 Maggio 2026 - AJAX browser, folder actions, Google Drive fix)
### 28 Maggio 2026 - AJAX Browser, Folder Actions, Google Drive + Bug Fixes
- **Download/Preview proxy**: Aggiunti `downloadRemote()` e `previewRemote()` in StorageRepositoryController — stream di file remoti per download e anteprima inline
- **Routes** (2 nuove): `GET /storage-repositories/{id}/download`, `GET /storage-repositories/{id}/preview`
- **AJAX browser**: Repository nel folder tree usano `browseRepo(repoId, nome, path)` via AJAX al `browse` endpoint — mostra cartelle e file remoti in grid/list view (stesso formato del file manager locale)
- **Funzioni JS**: `browseRepo()`, `loadRemoteContents()`, `renderRemoteContents()` (grid/list rendering), `downloadRepoFile()`, `previewRepoFile()`, `getFileIcon()` (MIME-type mapping), `showLocalContent()` — navigazione remota senza ricarica pagina
- **View toggle remoto**: `setView()` ora ricarica i contenuti remoti in grid/list se `currentRepoBrowse` è attivo
- **Folder tree rename**: Pulsante penna su hover → SweetAlert2 prompt → `PUT /documenti/cartelle/{id}` con `{nome}`
- **Folder tree delete**: Pulsante X rossa su hover → SweetAlert2 confirm → `DELETE /documenti/cartelle/{id}` (con warning se documenti/sottocartelle presenti nel controller)
- **Folder move**: `DocumentoCartellaController@update` ora accetta `parent_id` (con validazione anti-ciclo) — preparato per drag-and-drop futuro
- **CSS**: `.folder-actions` visibili su hover del `.list-group-item`
- **Google Drive fix**: Aggiunto `normalizePath()` in `StorageRepositoryService` — converte `/``''` per compatibilità cross-adapter (Google Drive non accetta `/` come root path). Usato in `testConnection()` e `listContents()`
- **testRepo() fix**: Passato `this` esplicitamente invece di `event.target` (che puntava all'`<i>` interno causando icona duplicata e disabilitazione errata del bottone)
- **Stato**: ✅ 18/19 test pass (solo ExampleTest pre-esistente). Sintassi PHP OK, view cache OK.
### 27 Maggio 2026 - Password Reset & Profile
@@ -749,3 +764,134 @@ php artisan route:list --name=email
- **6 nuovi report predefiniti** (18 totali): documenti_completo, scadenze_documenti, individui_completo, gruppi_completo, eventi_completo, contatti_completo
- **Tipologia filter**: I report `documenti_completo` e `scadenze_documenti` hanno dropdown inline Select2 per filtro tipologia nella card dell'index
- **Report index view**: Select2 multiselect per colonne, Select2 tipologia filter, sort direction, nuovi bottoni CSV export per custom reports
### 27 Maggio 2026 - Document Manager Rework (Cartelle + Storage Settings)
- **Migrations** (3 nuove):
- `2026_05_27_000001_create_documenti_cartelle_table.php` — tabella `documenti_cartelle` con `parent_id` FK self, `nome`, timestamps
- `2026_05_27_000002_add_cartella_id_to_documenti.php` — colonna `cartella_id` FK → `documenti_cartelle.id` su `documenti`
- `2026_05_27_000003_add_documenti_storage_to_app_settings.php` — colonne `documenti_storage_disk` (default `local`) e `documenti_storage_path` (default `documenti`) in `app_settings`
- **Model `DocumentoCartella`**: relazioni `parent()`, `children()`, `documenti()`, helper `ancestors()`, `fullPath()`
- **Model `Documento`**: aggiunto `cartella_id` in `$fillable`, nuova relazione `cartella()` (BelongsTo → DocumentoCartella). Tutte le relazioni esistenti (eventi/gruppi/individui/target/user/tenant) INTATTE
- **Model `AppSetting`**: aggiunti metodi `getDocumentiStorageDisk()`, `getDocumentiStoragePath()`, `getDocumentiStorageAbsolutePath()`
- **`DocumentoCartellaController`**: CRUD store/update/destroy + endpoint JSON `breadcrumb(id)` per breadcrumb navigazione
- **`DocumentoController` riscritto**:
- `index()`: filtra per `folder_id` GET param, passa `$cartelle` (struttura nidificata), `$currentFolder`, `$breadcrumb` alla view
- `store()`: accetta `cartella_id` opzionale, storage su disco dinamico da AppSetting
- `download/preview/destroy/massDestroy`: storage disk risolto dinamicamente via `resolveStorageDisk()`
- Tutti gli altri metodi (update, checkLinks, massUpdate, massAssociate) INALTERATI
- **`ImpostazioniController`**: `saveAppSettings()` valida e salva `documenti_storage_disk` (local|public) e `documenti_storage_path`
- **View `documenti/index.blade.php`**: riscritto come file manager a 3 colonne:
- Sidebar sinistra (col-md-3): folder tree con `list-group` e partial ricorsivo, link "Tutti i documenti", pulsante "+" Nuova Cartella
- Contenuto principale (col-md-9): breadcrumb navigazione, toolbar azioni massive, griglia card (col-md-4 each) con icona MIME-type, nome, tipologia badge, dimensione, data, autore, pulsanti azioni
- Stessi 6 modali esistenti (upload, associa, cambia tipo, preview, delete confirm, mass delete confirm) + nuovo modale "Nuova Cartella" AJAX
- JS: nuova funzione per submit AJAX del form nuova cartella con reload pagina
- **View `documenti/_folder_tree.blade.php`**: partial ricorsivo con `@include` per rendering folder tree annidato con indentazione progressiva
- **View `impostazioni/index.blade.php`**: nuova sezione "Repository Documenti" (tab-pane `#documenti`) con select disk, input path, path assoluto calcolato + alert informativo
- **Routes** (5 nuove):
- `POST /documenti/cartelle``DocumentoCartellaController@store`
- `PUT /documenti/cartelle/{id}``DocumentoCartellaController@update`
- `DELETE /documenti/cartelle/{id}``DocumentoCartellaController@destroy`
- `GET /documenti/cartelle/{id}/breadcrumb``DocumentoCartellaController@breadcrumb`
- `POST /documenti/mass-move``DocumentoController@massMove`
- **Mass Move**: Nuovo pulsante "Sposta selezionati in..." nella toolbar azioni massive, modal con stesso dropdown cartelle del move singolo, `massMove()` controller aggiorna `cartella_id` su `Documento::whereIn('id', $ids)`, JS handler submit form `/documenti/mass-move` con redirect/reload. Pulsante "+ Nuova cartella" nella modale con SweetAlert2 prompt e AJAX al backend
- **Cartelle miste a documenti (Opzione A)**: Controller `index()` passa `$sottoCartelle` (figli della cartella corrente, o root se nessuna filtrata) alla vista; griglia mostra folder card (fas fa-folder, card-warning) prima delle document card; lista mostra righe folder (tr class=table-warning) con colonne Nome/Cartella/-/-/-/Apri prima delle righe documento; empty state "Nessun elemento presente" se entrambi vuoti
- **Fix nested forms**: Aggiunto `</form>` di chiusura per `massForm` (linea 391) prima dei modali. Il form `massForm` avvolgeva tutto il contenuto incluse le modali, causando `<form>` nidificati (HTML invalido) — browser ignorava i form interni come `newFolderForm`, impedendo la creazione cartelle dal "+".
- **Verifica**: sintassi PHP ok, view cache ok, 8/9 test pass (solo ExampleTest pre-esistente fallisce)
- **Files creati**:
- `database/migrations/2026_05_27_000001_create_documenti_cartelle_table.php`
- `database/migrations/2026_05_27_000002_add_cartella_id_to_documenti.php`
- `database/migrations/2026_05_27_000003_add_documenti_storage_to_app_settings.php`
- `app/Models/DocumentoCartella.php`
- `app/Http/Controllers/DocumentoCartellaController.php`
- `resources/views/documenti/_folder_tree.blade.php`
- **Files modificati**:
- `app/Models/Documento.php`: cartella_id fillable + cartella() relation
- `app/Models/AppSetting.php`: metodi storage documenti
- `app/Http/Controllers/DocumentoController.php`: riscritto con filtro folder + storage dinamico
- `app/Http/Controllers/ImpostazioniController.php`: saveAppSettings validazione storage
- `resources/views/documenti/index.blade.php`: riscritto (file manager 3 colonne)
- `resources/views/impostazioni/index.blade.php`: nuova sezione Repository Documenti
- `routes/web.php`: 4 nuove rotte cartelle + import DocumentoCartellaController
(Last updated: 28 Maggio 2026 - Bug fix: JS syntax error, storage disk persistence)
### 28 Maggio 2026 - Bug Fix: JS syntax error, storage disk persistence
- **Problema 1 — Vista lista non funzionante**: `setView()` in `documenti/index.blade.php` aveva una `}` extra alla riga 1183 che causava `SyntaxError` JS. L'intero blocco `<script>` (1507 righe) non veniva parsato, rendendo inutilizzabili: toggle griglia/lista, renameFolder, deleteFolder, AJAX browser remoto, modali AJAX.
- **Fix**: Rimossa la `}` extra alla riga 1183.
- **Problema 2 — Icone cartelle assenti/non funzionanti**: Le icone rename/delete sono nel partial `_folder_tree.blade.php` con CSS hover (`.list-group-item:hover .folder-actions { display: inline-flex !important; }`). Le icone erano renderizzate nel DOM ma il JS era rotto: `renameFolder()` e `deleteFolder()` mai definite.
- **Fix**: Il fix del JS (rimozione `}` extra) risolve anche questo problema.
- **Problema 3 — Impostazione percorso locale non funzionante**: `AppSetting::getDocumentiStorageDisk()` veniva risolto dinamicamente sia in store che in download/preview/destroy. Cambiando il disco nelle impostazioni, i documenti caricati in precedenza non erano più accessibili (es. `local``public` causava 404 sui vecchi file).
- **Fix**: Creata migration `2026_05_28_000001_add_storage_disk_to_documenti.php` che aggiunge colonna `storage_disk` (nullable string) alla tabella `documenti`.
- `DocumentoController@store()` ora salva `storage_disk` sul record del documento.
- `resolveStorageDisk($documento)` ora restituisce il disco persistito se disponibile, altrimenti il default da AppSetting.
- Tutti i metodi (download, preview, destroy, massDestroy) usano `resolveStorageDisk($documento)` e beneficiano automaticamente del fix.
- **Stato**: ✅ 18/19 test pass (solo ExampleTest pre-esistente). `php -l` su tutti i file modificati OK. `php artisan view:cache` OK.
(Last updated: 28 Maggio 2026 - Folder icons, associa button, updateModal target, saveAppSettings fix)
### 28 Maggio 2026 - Folder Icons, Associa Button, UpdateModal Target, saveAppSettings Fix
- **Icone cartelle sempre visibili**: Rimosso `style="display:none;"` da `.folder-actions` in `_folder_tree.blade.php` — rename, move e delete sono ora sempre visibili, non solo su hover. CSS aggiornato: `.list-group-item .folder-actions { display: inline-flex; }`.
- **Aggiunto pulsante "Sposta" per cartelle**: Nuovo bottone `fa-folder-open` nel folder tree → funzione `moveFolder(id, nome)` con SweetAlert2 prompt contenente `<select>` con gerarchia cartelle (esclude se stessa e figli) → `PUT /documenti/cartelle/{id}` con `parent_id`. Aggiunti dati `folders` JSON in linea.
- **Aggiunto pulsante "Associa" per file singoli**: Bottone `fa-link` in ogni card (grid) e riga (list) → `showAssociateModal(id)` pre-popola il modale `#associateModal` con l'ID del documento singolo.
- **UpdateModal con target dinamico**: Aggiunto `#updateTargetGroup` nel modal "Cambia tipo/contesto": quando si seleziona `individuo`/`gruppo`/`evento`/`mailing`, compare dropdown con i dati caricati dagli array JS esistenti (`individui`, `gruppi`, `eventi`, `mailingLists`). Funzione `toggleUpdateTarget(value)` show/hide + popolamento.
- **massUpdate controller esteso**: `massUpdate()` in `DocumentoController` ora accetta `visibilita_target_id` e `visibilita_target_type` come parametri opzionali. Se presenti, aggiorna contesto + target sul DB con `$typeMap`.
- **Fix saveAppSettings null error**: `ImpostazioniController@saveAppSettings` ora preserva i valori esistenti quando i campi arrivano `null` (dovuto a `ConvertEmptyStringsToNull` middleware): `$settings->nome_applicazione = $validated[...] ?? $settings->nome_applicazione ?? ''`. Applicato a tutti i campi stringa. Risolve `SQLSTATE[23000]: Column 'nome_applicazione' cannot be null`.
- **Files modificati**:
- `app/Http/Controllers/ImpostazioniController.php`: saveAppSettings fallback valori esistenti
- `app/Http/Controllers/DocumentoController.php`: massUpdate esteso con target fields
- `resources/views/documenti/_folder_tree.blade.php`: always-visible icons + move button
- `resources/views/documenti/index.blade.php`: CSS always-visible, updateModal target dropdown, moveFolder() JS, showAssociateModal() JS, associa button su ogni file
- **Stato**: ✅ 18/19 test pass. `php -l` OK. `php artisan view:cache` OK.
(Last updated: 28 Maggio 2026 - Single-document "Cambia tipo/contesto" + mailing list fix in updateModal)
### 28 Maggio 2026 - Single-document "Cambia tipo/contesto" + mailing list fix
- **Aggiunto pulsante singolo "Cambia tipo/contesto"** su ogni documento:
- Grid view (card footer): bottone `fa-tag` dopo "Associa"
- List view (colonna azioni): stesso bottone per riga
- Nuova funzione JS `showUpdateModal(id)` pre-popola `updateIds` col singolo ID
- **Fix mailing list in updateModal**: `mailingLists` ora mappato a `{id, label}` via `.map(fn($m) => ['id' => $m->id, 'label' => $m->nome])`
- **Files modificati**:
- `resources/views/documenti/index.blade.php`: bottoni su grid+list, funzione `showUpdateModal()`, mapping mailing list corretto
- **Stato**: ✅ `php -l` OK. `php artisan view:cache` OK.
### 28 Maggio 2026 - Folder action icons (grid/list view) + mass download ZIP
- **Aggiunte icone azioni cartelle in griglia e lista** (non solo sidebar tree):
- Grid view: card-footer con pulsanti Rinomina, Sposta, Elimina per ogni cartella
- List view: colonna azioni con pulsanti Rinomina, Sposta, Elimina per ogni riga cartella
- **Nuova mass action "Scarica"**: pulsante nella toolbar azioni massive
- Crea un archivio ZIP con `ZipArchive` contenente i file selezionati
- Supporta sia documenti locali che da repository remoti
- Download monouso (`response()->download()->deleteFileAfterSend(true)`)
- In caso di file non accessibili, li salta e include solo quelli disponibili
- **Files modificati**:
- `routes/web.php`: nuova route `POST /documenti/mass-download`
- `app/Http/Controllers/DocumentoController.php`: nuovo metodo `massDownload()`
- `resources/views/documenti/index.blade.php`: icone cartelle in grid+list, bottone "Scarica" mass action, funzione JS `massDownload()`
- **Stato**: ✅ 18/19 test pass (solo ExampleTest pre-esistente). `php -l` OK. `php artisan view:cache` OK.
### 28 Maggio 2026 - Fix pagina bloccata: massaAction() mancante di chiusura }
- **Problema**: La funzione `massAction()` nel JS di `documenti/index.blade.php` aveva un `}` di chiusura mancante, causando:
- Tutto il JS successivo (tutte le funzioni) veniva interpretato come annidato dentro massAction
- Le funzioni non erano accessibili globalmente → icone azioni click non funzionanti (renameFolder, deleteFolder, showUpdateModal, ecc.)
- La pagina risultava bloccata/non reattiva
- **Causa**: Introdotto nel refactoring file manager (27 Maggio), il `}` finale di `function massAction()` era stato perso. Il codice originale in git HEAD aveva 3 `}` di chiusura (catch + if + function), il file corrente ne aveva solo 2.
- **Fix**: Aggiunto `}` mancante per chiudere `massAction()`.
- **Verifica**: 182 `{` = 182 `}` nel blocco JS. 18/19 test pass. `php -l` OK. `php artisan view:cache` OK.
### 28 Maggio 2026 - Fix: delete redirect, folder azioni non funzionanti, escaping JS
- **Fix delete redirect dashboard**: `DocumentoController@destroy()` usava `url('/')` come default redirect → dopo eliminazione si finiva in dashboard. Cambiato a `url()->previous()`.
- **Fix folder azioni non funzionanti**: Tutti gli onclick handler per renameFolder/moveFolder/deleteFolder usavano `addslashes()` che non gestisce correttamente apici nei nomi in contesto HTML → JS error silenzioso, funzioni non eseguite. Sostituito con `json_encode()` che produce stringhe JS correttamente escaped con virgolette.
- **Fix browseRepo repo names**: Stesso fix `addslashes``json_encode` per i nomi repository negli onclick.
- **Files modificati**:
- `app/Http/Controllers/DocumentoController.php`: destroy() redirect default `url()->previous()`
- `resources/views/documenti/index.blade.php`: 10 onclick con `json_encode` invece di `addslashes`
- `resources/views/documenti/_folder_tree.blade.php`: 3 onclick con `json_encode` invece di `addslashes`
- **Stato**: ✅ 18/19 test pass. `php -l` OK. `php artisan view:cache` OK. JS braces 182/182.