- eventi/create.blade.php: "Dove" card with address + Google Maps URL fields
- eventi/edit.blade.php: "Dove" card with address + Google Maps URL fields
- eventi/show.blade.php: "Luogo" section with address, link to Google Maps, embedded map preview
### Responsabile Multi-select (Completed)
- Migration `2026_05_12_000003_change_responsabile_to_multi.php` changed `responsabile_id` to `responsabile_ids` JSON
- Gruppo model updated with `getResponsabiliIds()` and `getResponsabili()` methods
- GruppoController updated: index(), store(), update(), show() for multi-select
- Views updated: show, edit, create blades with multi-select support
### 13 Maggio 2026 - Fixes
- **Ordinamento colonne**: Aggiunto ordinamento per Descrizione, Tipo, Gruppi, Responsabili
- **Form edit**: Aggiunti campi `tipo_evento` e `note` mancanti
- **Show view**: Corretta struttura HTML della sezione documenti
### 14 Maggio 2026 - Fixes
- **Form annidati**: La sezione Documenti spostata FUORI dal form principale
- **Tipologia enum**: Aggiunti valori 'programma' e 'locandina' alla colonna tipologia in documenti
- **Visibilita enum**: Aggiunto valore 'evento' alla colonna visibilita in documenti
### 15 Maggio 2026 - Eventi Show
- Rimossa sezione "Dove" duplicata dalla sidebar
- Aggiunta nuova sezione "Luogo" sotto "Data e Orario" nella colonna centrale
### 15 Maggio 2026 - Email Settings
- Aggiunto pulsante "Test Invio Email (SMTP)" nella pagina impostazioni email
- Aggiunto metodo `testSmtp()` nel controller per verificare la configurazione SMTP
- Route: `POST /impostazioni/email/test-smtp`
- Campo password opzionale (non più required)
- Rimossi attributi required dai campi del form impostazioni email
### 15 Maggio 2026 - Eventi Calendar
- Nuova vista calendario con FullCalendar 6.1.10
- Routes: `GET /eventi/calendar` e `GET /eventi/calendar/events`
- Metodo `calendar()` e `calendarEvents()` in EventoController
- Sidebar: menu Eventi con sottovoci Calendario, Elenco, Nuovo Evento
- Click su evento apre la pagina show dell'evento
### 15 Maggio 2026 - Email UI
- **Compose view**: Rimossa sidebar sinistra, solo form a schermo intero
- **Sidebar menu Email**:
- Ordine: Nuova Email, In arrivo, Preferiti, Inviate, Bozze, Archivio, Cestino
- Cliccando "Email" apre direttamente inbox
- **Bottone sincronizzazione**: "Ricevi/Invia" nella pagina inbox
- **Sincronizzazione**: Limitata a 100 messaggi per cartella
### 15 Maggio 2026 - Bug Fixes
- **RFC 2822**: Usare `Address::create()` di Symfony per gestire correttamente il display name
- **Route email.sync**: Sostituito `route('email.sync.quick')` con `url('email/sync/quick')` nella vista email/index.blade.php
### 16 Maggio 2026 - Email UI Fixes
- **Footer**: Aggiunto `min-height: calc(100vh - 120px)` al content-wrapper per garantire visibilità footer
- **Pagination**: Creato custom view `vendor.pagination.simple-bootstrap-4` con caratteri `‹` e `›` invece di SVG (problema scalabilità risolto)
### 16 Maggio 2026 - Logo Upload System
- **Model**: `App\Models\AppSetting` con metodi `getLogoUrl()`, `getLogoSmallUrl()`, `getAppName()`
- **Migration**: `2026_05_16_000001_add_logo_path_to_app_settings` - aggiunge `logo_path` e `logo_small_path`
- **Controller**: `ImpostazioniController` - metodi `uploadLogo()` e `removeLogo()`
- **Problema**: Errore "syntax error, unexpected token 'endif'" nella dashboard
- **Causa**: Dopo aver rimosso il blocco `@if(Auth::user()->isSuperAdmin())` dalla sidebar per sostituirlo con `@if(Auth::user()->canAccess('report'))`, erano rimasti un `@endif` orfano (linea 237) e un `</li>` extra (linea 239)
- **Soluzione**:
1. Rimosso `@endif` orfano
2. Rimosso `</li>` extra
3. Aggiunto nuovo `@if(Auth::user()->isSuperAdmin())` per proteggere i menu Impostazioni e Admin
- **Verifica completa**: Scansionati tutti i blade file del progetto - tutte le direttive `@if/@endif`, `@foreach/@endforeach`, `@php/@endphp` sono correttamente bilanciate. Compilazione viste OK.
### 25 Maggio 2026 - Accesso Report Basato su Permessi
- **Modifica**: Il modulo 'report' è stato aggiunto a `User::MODULES` come nuovo modulo permissionabile
- **Funzionalità**: Gli utenti con permesso `canAccess('report')` (livello lettura o superiore) possono accedere alla pagina Report, non più solo il superadmin
- `app/Http/Controllers/DocumentoController.php`: logica esplicita per mappare visibilità → target_type
### 25 Maggio 2026 - Fix Pagina Gruppi (Tabella Pivot Inesistente)
- **Problema**: Pagina gruppi falliva con "Table 'glastree.gruppo_responsabili' doesn't exist"
- **Causa**: Il modello `Gruppo` aveva una relazione `responsabili()` che puntava a tabella pivot inesistente (la migration `2026_05_12_000003` aveva migrato a JSON `responsabile_ids`)
- **Soluzione**:
1. Rimossa relazione `responsabili()` da `Gruppo.php`
2. Rimossa eager loading `responsabili` da `GruppoController@index()`
3. Mantenuti metodi helper `getResponsabiliIds()` e `getResponsabili()` che leggono dal campo JSON
4. Corretti riferimenti in `gruppi/show.blade.php` e `individui/show.blade.php` per usare `getResponsabili()`
- **Impostazioni view**: Nuovo tab `#tipologie-eventi` con tabella sortabile, modali add/edit, stessi pattern esistenti
- **Sidebar**: Nuovo link "Tipologie Eventi" sotto Impostazioni (solo superadmin)
- **Evento model**: Aggiunta relazione `tipologiaEvento()` (BelongsTo via 'nome')
- **EventoController**: Validazione cambiata da `nullable|string|max:100` a `nullable|exists:tipologie_eventi,nome` in store() e update(); create/edit passano `$tipologieEventi` alla view
- **Views eventi**:
- `create.blade.php`: Dropdown "Tipo Evento" dopo Descrizione Breve
- `edit.blade.php`: Text libero → dropdown; fallback per vecchi valori non presenti
- `show.blade.php`: Badge "Tipologia" nella sezione Data e Orario; colonna rinominata "Ricorrenza"
- `index.blade.php`: Nuova colonna sortabile "Tipologia" con badge; colonna "Tipo" → "Ricorrenza"; colspan 8→9
### 26 Maggio 2026 - ACL Fixes & Form Modules Sync
- **Problema**: Form admin utenti (create/edit) aveva lista moduli hardcoded e mancante di `'report'`; user 4 (fbarachino) non aveva permesso `report` né `is_admin`
- **Fix form edit/create**: Sostituito `@foreach(['individui', 'gruppi', 'eventi', 'documenti', 'mailing', 'viste'] as $module)` con `@foreach(\App\Models\User::MODULES as $module)` in entrambe le view (`edit.blade.php:76`, `create.blade.php:66`) — ora la lista è sempre allineata alla costante `User::MODULES`
- **Fix user 4**:
- Aggiunto `'report' => 2` alle permissions (full access)
- Itera tutti gli utenti (inclusi superadmin) e aggiunge con default 0 ogni modulo mancante in `User::MODULES`
- Previene discrepanze future tra permissions salvate e MODULES costante
- **Files modificati**:
- `resources/views/admin/utenti/edit.blade.php`: linea 76, hardcoded → `User::MODULES`
- `resources/views/admin/utenti/create.blade.php`: linea 66, hardcoded → `User::MODULES`
- **File creato**:
- `app/Console/Commands/SyncUserPermissions.php`: nuovo comando artisan
- **Stato sidebar user 4**: `isSuperAdmin()` = true → tutti i menu visibili, `canAccess('report')` = true
### 26 Maggio 2026 - ACL 'settings' Module (Impostazioni/Admin Permission)
- **Problema**: Non esisteva un permesso ACL specifico per accedere al menu Impostazioni e Admin. L'accesso era legato esclusivamente a `isSuperAdmin()` bypass totale. Inoltre l'`ImpostazioniController` usava `authorizeWrite('viste')` come piggyback scorretto.
- **Soluzione**: Nuovo modulo `settings` separato, slegato da `viste` e da `isSuperAdmin()`.
- **Modifiche**:
- `User.php`: aggiunto `'settings'` a `MODULES` (costante linea 36)
- `adminlte.blade.php` sidebar: `@if(Auth::user()->isSuperAdmin())` → `@if(Auth::user()->canManage('settings'))` per menu Impostazioni e Admin (linee 205-226)
- `AdminOnly.php` middleware: `isSuperAdmin()` → `isSuperAdmin() || canManage('settings')` — permette accesso a `/admin/*` anche a non-superadmin con permesso settings:2
- `ImpostazioniController.php`: rimpiazzate tutte le 16 occorrenze di `authorizeWrite('viste')` e `authorizeDelete('viste')` con `'settings'`
- `EmailSettingsController.php`: aggiunto `$this->authorizeWrite('settings')` in tutti i 5 metodi pubblici (index, save, testConnection, testSmtp, syncNow) — prima non avevano alcuna autorizzazione esplicita
- `SyncUserPermissions.php` aggiornato: ora include anche superadmin nella sync (per consistenza dati)
- Eseguito `php artisan users:sync-permissions` → user 1 e 4 aggiornati con `settings: 0`
- **Comportamento risultante**:
- `isSuperAdmin()` bypassa sempre tutto (base Controller.php)
- Utente normale con `settings:2` (Completo) → vede menu Impostazioni+Admin, può operare
- Utente normale con `settings:0` → menu nascosto, 403 su accesso diretto URL
- `settings:1` (Lettura) non basta per operazioni di scrittura (sidebar non mostra il menu perché richiede `canManage`)
- `app/Console/Commands/SyncUserPermissions.php`: superadmin inclusi nella sync
### 26 Maggio 2026 - Fix Salvataggio is_admin (Checkbox Superadmin)
- **Problema**: Non era possibile togliere il flag "Superadmin (bypass ACL)" dall'interfaccia admin. Il flag rimaneva sempre true dopo il salvataggio.
- **Cause** (3 bug concatenati):
1. **`url()` assoluto** nell'action del form edit (`url('/admin/utenti/' . $user->id)`) → da accesso remoto generava `http://localhost/admin/utenti/4`, il POST falliva silenziosamente
2. **Nessun hidden field** per unchecked checkbox → quando la checkbox veniva deselezionata, il campo `is_admin` non veniva inviato nella richiesta. Anche se il controller aveva `?? false`, il combinato col bug #1 impediva il salvataggio
3. **Mancanza `old()`** per lo stato checkbox → su validation error redirect, la checkbox mostrava il valore DB invece del valore inviato
- **Fix applicati**:
- `edit.blade.php`: `url(...)` → path relativo `/admin/utenti/...` (linea 20); aggiunto hidden `<input type="hidden" name="is_admin" value="0">` prima della checkbox; `old()` per stato checkbox e status/role_preset_id
- `create.blade.php`: aggiunto hidden field come sopra; default per `settings` = `'0'` (Nessuno) invece di `'1'` (Lettura) per nuovi utenti
- `UtenteController.php` (store + update): rimosso `?? false` da `$user->is_admin` — ora usa direttamente `$validated['is_admin']` (sempre presente grazie all'hidden field)
- `AuthController.php`: aggiunti `'report' => 0` e `'settings' => 0` ai default permissions per nuove registrazioni (sia first-user che non)
- **Files modificati**:
- `resources/views/admin/utenti/edit.blade.php`: form action, hidden field, old()
- `buildSymfonyEmail(to, subject, body)` — costruisce email con From, Reply-To
- `sendEmail(to, subject, body, attachmentPaths)` — invia via Symfony Mailer
- `sendReport(subject, body)` — invia report riepilogo a `verify_email`
- **Logica Reply-To**: se impostato `reply_to` (es. `no-reply@parrocchia.it`) → quello; fallback `verify_email`; nessun Reply-To se entrambi null
- **Report invio**: dopo ogni invio massivo via sender, una email di riepilogo viene inviata a `verify_email` con: mittente, oggetto, totale, ok, falliti, dettaglio errori
-`show.blade.php`: pulsante "Esporta ICS" nella toolbar azioni
-`index.blade.php`: pulsante "Esporta ICS" nella card-tools; se ci sono righe selezionate esporta solo quelle, altrimenti esporta tutti i risultati della ricerca corrente
-`calendar.blade.php`: pulsante "Esporta ICS" che esporta tutti gli eventi
### 27 Maggio 2026 - Mittenti Aggiuntivi in Sezione Email di /impostazioni
- **Modifica**: Spostata gestione sender accounts (Mittenti Aggiuntivi) da pagina dedicata `/impostazioni/email` a **sottosezione della sezione Email** nella pagina principale `/impostazioni`
- **Sub-tab aggiunto**: pill "Mittenti Aggiuntivi" dopo Firma nei sottotab della sezione Email
- **Tab-pane `email-mittenti`**: tabella sender con colonne Email, Nome, SMTP, Reply-To, Verify, Stato, Azioni; stessi campi CRUD della vista dedicata
- **Form puliti**: pulsanti Elimina usano fetch AJAX (`deleteSender()`) invece di form annidati per evitare HTML invalido (nested forms dentro il form principale Email)
- **Controller**: `ImpostazioniController@index` ora passa `$senderAccounts` alla view
- **`senderDestroy()`** in `EmailSettingsController`: ora ritorna JSON per richieste AJAX (`expectsJson()`)
- **Sidebar**: rimossa voce "Impostazioni Email" aggiunta in precedenza sotto Email (non serve — le impostazioni email sono accessibili dalla sezione Email in `/impostazioni`)