diff --git a/MEMORY.md b/MEMORY.md index b82d0870..3c32d664 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -90,8 +90,37 @@ php artisan config:clear **Fix**: Spostato il form DELETE fuori dal form SAVE, separato in un `div` autonomo. +### Fix campi mancanti in validazione EmailSettingsController@save +**2026-06-08**: `signature`, `signature_enabled`, `smtp_username`, `smtp_password` non erano nelle regole di validazione di `save()`. Laravel scarta i campi non validati, quindi non venivano mai scritti nel DB. + +**Fix**: Aggiunte le regole mancanti a `$request->validate()`. + ### DiagnoseEmail Command - `php artisan diagnose:email` — controlla APP_KEY, tabella email_settings, record, decrittazione password, sender_accounts, log errori, estensioni PHP. +### 2026-06-08 — Firma email ancora non salvata (secondo tentativo) +**Problema**: La firma (campo `signature`) non veniva salvata nonostante le regole di validazione fossero state aggiunte. + +**Root cause analysis**: +1. HTML checkbox `signature_enabled` senza hidden fallback: quando non spuntato, il campo non veniva inviato → non presente in `$validated` → `updateOrCreate` non lo aggiornava mai a `false`. +2. La vecchia pagina `/impostazioni/` aveva l'handler `shown.bs.tab` per il tab Firma (`#email-firma`) in un solo punto su due, causando possibile mancata inizializzazione dell'editor Quill su alcuni flussi di navigazione. +3. La verifica nel controller controllava solo `imap_host` e `email_address` — anche se signature/signature_enabled fallivano, l'utente vedeva "salvato con successo". + +**Fix**: +1. `resources/views/admin/email-settings/index.blade.php:268` — Aggiunto `` prima della checkbox +2. `resources/views/impostazioni/index.blade.php:603` — Stesso hidden fallback +3. `resources/views/impostazioni/index.blade.php:1633` — Aggiunto `#email-firma` al primo handler `shown.bs.tab` (il secondo handler esisteva già ma il primo no) +4. `app/Http/Controllers/Admin/EmailSettingsController.php:70-82` — Aggiunto log di warning se signature o signature_enabled non corrispondono dopo il salvataggio + +### 2026-06-08 — Sync email: "Nessuna configurazione email attiva" nonostante test IMAP funzioni +**Problema**: Cliccando "Sincronizza Ora" nelle impostazioni email o "Ricevi/Invia" nella pagina email, viene mostrato "Nessuna configurazione email attiva". Il test IMAP funziona correttamente. + +**Root cause**: Stesso bug dei checkbox senza hidden fallback. Il campo `is_active` nel tab Sincronizzazione non veniva inviato quando non spuntato. Alla prima configurazione, se l'utente non visitava esplicitamente il tab Sync e attivava lo switch, `is_active` rimaneva `false` (default DB). Il test IMAP usa `EmailSetting::first()` (ignora `is_active`), mentre `syncEmails()` e `syncNow()` usano `EmailSetting::getActive()` che filtra per `is_active = true`. + +**Fix**: +1. `resources/views/admin/email-settings/index.blade.php:251` — Aggiunto `` prima della checkbox +2. `resources/views/impostazioni/index.blade.php:586` — Stesso hidden fallback +3. `EmailSetting::getActive()` ora riceve sempre `is_active` dal form (0 o 1) grazie all'hidden fallback + ## Prossimi Passi - *(nessuno — in attesa di nuove richieste)* diff --git a/app/Http/Controllers/Admin/EmailSettingsController.php b/app/Http/Controllers/Admin/EmailSettingsController.php index 31f593fd..34888f64 100644 --- a/app/Http/Controllers/Admin/EmailSettingsController.php +++ b/app/Http/Controllers/Admin/EmailSettingsController.php @@ -34,11 +34,15 @@ class EmailSettingsController extends Controller 'smtp_host' => 'nullable|string|max:255', 'smtp_port' => 'nullable|integer|min:1|max:65535', 'smtp_encryption' => 'nullable|in:ssl,tls,none', + 'smtp_username' => 'nullable|string|max:255', + 'smtp_password' => 'nullable|string', 'email_address' => 'required|email', 'email_name' => 'nullable|string|max:255', 'reply_to' => 'nullable|email', 'sync_interval_minutes' => 'nullable|integer|min:1|max:60', 'is_active' => 'boolean', + 'signature' => 'nullable|string', + 'signature_enabled' => 'boolean', ]); if (!empty($validated['imap_password'])) { @@ -62,6 +66,24 @@ class EmailSettingsController extends Controller if ($verify && $verify->imap_host === $validated['imap_host'] && $verify->email_address === $validated['email_address']) { + + $signatureMatch = !array_key_exists('signature', $validated) || $verify->signature === $validated['signature']; + $signatureEnabledMatch = !array_key_exists('signature_enabled', $validated) || (bool)$verify->signature_enabled === (bool)$validated['signature_enabled']; + + if (!$signatureMatch) { + \Illuminate\Support\Facades\Log::warning('Signature mismatch after save', [ + 'expected' => $validated['signature'] ?? null, + 'actual' => $verify->signature, + ]); + } + + if (!$signatureEnabledMatch) { + \Illuminate\Support\Facades\Log::warning('Signature enabled mismatch after save', [ + 'expected' => $validated['signature_enabled'] ?? null, + 'actual' => $verify->signature_enabled, + ]); + } + return back()->with('success', 'Impostazioni email salvate e verificate nel database.'); } else { return back()->with('error', 'Errore nel salvataggio: i dati non sono stati salvati correttamente.'); diff --git a/resources/views/admin/email-settings/index.blade.php b/resources/views/admin/email-settings/index.blade.php index 2b929fc1..ec9189df 100644 --- a/resources/views/admin/email-settings/index.blade.php +++ b/resources/views/admin/email-settings/index.blade.php @@ -248,6 +248,7 @@
+ is_active ?? false) ? 'checked' : '' }}> @@ -265,6 +266,7 @@
+ signature_enabled ?? true) ? 'checked' : '' }}> diff --git a/resources/views/impostazioni/index.blade.php b/resources/views/impostazioni/index.blade.php index 4b7b3ef3..2d90a13d 100644 --- a/resources/views/impostazioni/index.blade.php +++ b/resources/views/impostazioni/index.blade.php @@ -583,6 +583,7 @@
+ is_active ?? false) ? 'checked' : '' }}> @@ -599,11 +600,12 @@
-
- signature_enabled ?? true) ? 'checked' : '' }}> - -
+
+ + signature_enabled ?? true) ? 'checked' : '' }}> + +
Quando attivo, la firma verrà aggiunta in fondo a ogni email inviata

@@ -1629,6 +1631,9 @@ $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { sortableCalendario.refresh(); } } + if (target === '#email-firma') { + setTimeout(initSignatureEditor, 100); + } }); // ===== MITTENTI AGGIUNTIVI ===== diff --git a/storage/framework/views/a54cb906b71ecddfe8edf55b3671046a.php b/storage/framework/views/a54cb906b71ecddfe8edf55b3671046a.php deleted file mode 100755 index fedcf501..00000000 --- a/storage/framework/views/a54cb906b71ecddfe8edf55b3671046a.php +++ /dev/null @@ -1,962 +0,0 @@ - -startSection('title', 'Guida - ' . $appName); ?> -startSection('page_title', 'Guida alla Configurazione'); ?> -startSection('breadcrumbs'); ?> - - -stopSection(); ?> - -startSection('content'); ?> -
- - -
-
- -
-
-
-

WebDAV / Nextcloud

-
-
-
Cos'è
-

WebDAV è un protocollo che permette di accedere a file su server remoti. Nextcloud lo utilizza per la sincronizzazione dei file.

- -
Configurazione
-

Vai in Impostazioni → Repository e crea un nuovo repository di tipo WebDAV.

- -
-
Campi obbligatori
-
-
Nome
-
Un nome descrittivo (es. "Nextcloud Lavoro")
-
Base URI
-
L'URL del tuo server WebDAV. -
Nextcloud: https://tuodominio.it/remote.php/dav/files/utente/ -
Altri: https://server.webdav.it/
-
Root
-
Percorso base all'interno del server (es. /Documenti/). Lascia / per usare la root.
-
Username
-
Il tuo nome utente
-
Password
-
La password dell'account
-
Auth Type
-
Basic per la maggior parte dei server (Nextcloud, ownCloud).
-
-
- -
⚠️ Nome utente con @ (chiocciola)
-

Se il tuo nome utente contiene il carattere @ (es. mario.rossi@azienda.com), segui queste regole:

-
    -
  • Nel campo "Base URI": l'indirizzo email deve essere URL-encoded: -
    https://server.it/remote.php/dav/files/mario.rossi%40azienda.com/ -
    (il carattere @ diventa %40)
  • -
  • Nel campo "Username": inserisci l'indirizzo email normale con la @ vera.
  • -
-
- - Il sistema gestisce automaticamente la differenza tra l'URI (che richiede %40) e l'autenticazione (che usa la @ reale). -
- -
Test connessione
-

Dopo aver salvato, usa il pulsante Test nella tabella dei repository per verificare che la connessione funzioni.

- -
Importare file
-

Apri la sezione Documenti, clicca sul pulsante del repository nella toolbar per sfogliare i file remoti, poi clicca Salva tra i documenti su un file per importarlo come documento locale.

-
-
-
- - -
-
-
-

Google Drive

-
-
-
Cos'è
-

Integrazione con Google Drive per sfogliare e importare file direttamente dal tuo spazio Google Drive.

- -
Requisiti
-
    -
  1. Un account Google / Google Workspace
  2. -
  3. Un progetto sulla Google Cloud Console con l'API Google Drive abilitata
  4. -
  5. Credenziali OAuth 2.0 (Client ID e Client Secret)
  6. -
- -
Passo 1: Creare il progetto Google Cloud
-
    -
  1. Vai su Google Cloud Console
  2. -
  3. Crea un nuovo progetto o selezionane uno esistente
  4. -
  5. Vai a API e servizi → Libreria
  6. -
  7. Cerca "Google Drive API" e abilitala
  8. -
  9. Vai a API e servizi → Credenziali
  10. -
  11. Clicca "Crea credenziali → ID client OAuth"
  12. -
  13. Tipo applicazione: "Applicazione Web"
  14. -
  15. URI di reindirizzamento autorizzato: aggiungi
  16. -
  17. Completa la creazione e copia Client ID e Client Secret
  18. -
- -
Passo 2: Configurazione nell'app
-
    -
  1. Vai in Impostazioni → Repository
  2. -
  3. Clicca "Nuovo Repository" e seleziona tipo Google Drive
  4. -
  5. Inserisci un nome descrittivo (es. "Drive Lavoro")
  6. -
  7. Incolla Client ID e Client Secret
  8. -
  9. Folder ID (opzionale): se vuoi limitare l'accesso a una cartella specifica, inserisci il suo ID (lo trovi nell'URL quando apri la cartella in Google Drive: https://drive.google.com/drive/folders/ID_QUI)
  10. -
  11. Clicca "Autorizza Google Drive" — verrai reindirizzato a Google per concedere i permessi
  12. -
  13. Dopo l'autorizzazione, il refresh token verrà salvato automaticamente
  14. -
- -
⚠️ Google Drive API non abilitata
-

Se vedi l'errore "Google Drive API non abilitata" nel test connessione, significa che l'API Drive non è stata attivata nel tuo progetto Google Cloud.

-
-
Soluzione
-

Vai su - https://console.developers.google.com/apis/api/drive.googleapis.com/overview -

-

Seleziona il progetto corretto dall'header in alto, clicca "Enable" e attendi qualche minuto prima di riprovare.

-
- -
Importare file
-

Stessa procedura di WebDAV: apri Documenti, clicca sul repository Drive, sfoglia i file e usa Salva tra i documenti.

- -
⚠️ File Google (Documenti, Fogli, Presentazioni)
-

I file creati con Google Workspace (Documenti Google, Fogli Google, Presentazioni Google, Disegni Google) non possono essere scaricati direttamente perché non hanno un formato binario nativo.

-

Il sistema li converte automaticamente in formato Office Open XML durante l'import:

- - - - - - - - - -
File GoogleFormato convertito
Documento Google.docx (Word)
Foglio Google.xlsx (Excel)
Presentazione Google.pptx (PowerPoint)
Disegno Google.png (Immagine)
Altri (Moduli, Script).pdf (PDF)
-
- - Il nome del file viene automaticamente esteso con l'estensione corretta (es. "Relazione" → "Relazione.docx"). -
-
-
-
- - -
-
-
-

Tipologie e Gestione Dati

-
-
-
Tipologie Documenti
-

Le tipologie classificano i documenti (avatar, galleria, documento, statuto, altro).

-

Si gestiscono in Impostazioni → Tipologie Documenti. Puoi aggiungere, rinominare, riordinare ed eliminare tipologie (tranne quelle con documenti associati).

- -
Tipologie Individui
-

Classificano gli individui (es. socio, volontario, dipendente). Si gestiscono in Impostazioni → Tipologie.

- -
Tipologie Eventi
-

Classificano gli eventi (es. riunione, assemblea, formazione). Si gestiscono in Impostazioni → Tipologie Eventi.

- -
Ruoli Individui
-

Definiscono il ruolo o la carica di un individuo (es. presidente, segretario, tesoriere). Si gestiscono in Impostazioni → Ruoli.

- -
Visibilità Documenti
-

Ogni documento può avere diversi livelli di visibilità:

-
    -
  • Pubblico — visibile a tutti gli utenti
  • -
  • Individuo — visibile solo a uno specifico individuo
  • -
  • Gruppo — visibile solo ai membri di un gruppo
  • -
  • Evento — visibile solo ai partecipanti di un evento
  • -
  • Mailing — visibile solo ai membri di una mailing list
  • -
-
-
-
- - -
-
-
-

Email / SMTP

-
-
-
Configurazione Email
-

Vai in Impostazioni → Email per configurare la posta elettronica.

- -
Server IMAP (Ricezione)
-

Usato per ricevere e leggere le email direttamente nell'app.

-
-
Campi consigliati per provider comuni
- - - - - - - - -
ProviderHostPortaCrittografia
Gmailimap.gmail.com993SSL
Outlook/Office 365outlook.office365.com993SSL
Liberoimapmail.libero.it993SSL
Arubaimap.aruba.it993SSL
-
- -
Server SMTP (Invio)
-

Usato per inviare email dall'app. Supporta account multipli (mittenti).

-
-
Campi consigliati per provider comuni
- - - - - - - - -
ProviderHostPortaCrittografia
Gmailsmtp.gmail.com587TLS
Outlook/Office 365smtp.office365.com587TLS
Liberosmtp.libero.it465SSL
Arubasmtp.aruba.it465SSL
-
- -
Gmail / Google Workspace
-
- - Gmail richiede una Password per l'app (non la password normale) se usi la verifica in due passaggi. Puoi generarla su - https://myaccount.google.com/apppasswords. -
- -
Mailing
-

Le Mailing List permettono di inviare email a gruppi predefiniti di destinatari.

-
    -
  • Crea una mailing list in Mailing List → Nuova
  • -
  • Puoi popolare la lista da individui, gruppi o manualmente
  • -
  • Invia email alla lista da Email → Nuova Email, selezionando la mailing list come destinatario
  • -
- -
Test connessione
-

Dopo aver configurato i server, usa il pulsante Test Connessione per verificare che IMAP e SMTP funzionino correttamente.

-
-
-
- - -
-
-
-

Backup e Migrazione Server

-
-
-
Cos'è
-

Il sistema di backup crea un archivio ZIP contenente tutto il necessario per ripristinare l'applicazione su un nuovo server. Include database, file caricati e configurazione.

- -
Cosa include il backup
- - - - - - - - -
ComponenteInclusoDettagli
Database (MySQL)SempreStruttura, dati, stored procedure, eventi, trigger
File caricatiOpzionaleDocumenti, avatar, gallerie
Configurazione .envOpzionaleAPP_KEY, credenziali DB, SMTP, token OAuth
MetadatiSempreVersione app, PHP, Laravel
- -
Come eseguire un backup
-
-
-
-
Via Interfaccia Web
-
    -
  1. Vai su Admin → Backup
  2. -
  3. Verifica le impostazioni (includi files/.env)
  4. -
  5. Clicca Esegui Backup Ora
  6. -
  7. Scarica il file ZIP generato
  8. -
-
-
-
-
-
Via Comando
-
php artisan backup:run
-

Il file viene creato in storage/app/backups/

-
-
-
- -
Backup automatico
-

Puoi abilitare il backup automatico dalla pagina Admin → Backup:

-
    -
  • Frequenza: giornaliero, settimanale o mensile
  • -
  • Ora: consigliata 03:00 (notte)
  • -
  • Requisito: il cron di Laravel deve essere configurato sul server
  • -
-
- - Per il backup automatico, aggiungi questo cron: -
* * * * * cd  && php artisan schedule:run >> /dev/null 2>&1
-
- -
- -

Procedura di Migrazione Completa

-

Segui questa procedura per migrare l'applicazione su un nuovo server LAMP (Linux, Apache, MySQL, PHP).

- -
- - ATTENZIONE: APP_KEY -

L'APP_KEY cripta i dati sensibili (password email SMTP, token OAuth Google Drive, ecc.).

-
    -
  • Se hai il .env originale dal backup: NON rigenerare APP_KEY — mantieni i dati criptati accessibili.
  • -
  • Se hai perso il .env: DEVI rigenerare APP_KEY, ma perderai l'accesso ai dati criptati esistenti. Dovrai riconfigurare SMTP e OAuth.
  • -
-
- -
Passo 1: Preparazione del server
-
sudo apt update && sudo apt upgrade -y
- -
Passo 2: Installa LAMP + PHP 8.4
-
sudo apt install -y apache2 mariadb-server php8.4 php8.4-cli \
-  php8.4-mysql php8.4-xml php8.4-mbstring php8.4-curl \
-  php8.4-zip php8.4-bcmath php8.4-gd php8.4-intl \
-  composer git unzip
-
-sudo a2enmod rewrite
- -
Passo 3: Ottieni l'applicazione
-
- - Puoi clonare il repository con git oppure estrarre il file ZIP ricevuto nella cartella /var/www/glastree. -
-
cd /var/www
-
-# Opzione A — Git clone
-git clone <URL_REPOSITORY> glastree
-
-# Opzione B — ZIP (se non hai git)
-# unzip /percorso/del/glastree.zip -d glastree
-
-cd glastree
-composer install --no-dev --optimize-autoloader
-npm ci && npm run build
- -
Passo 4: Carica il backup
-

Copia il file backup.zip sul nuovo server e estrailo:

-
mkdir -p /tmp/restore
-unzip backup.zip -d /tmp/restore/
-ls -la /tmp/restore/
-# Dovresti vedere: database.sql  .env  files/  manifest.json
- -
Passo 5: Crea database e importa
-
sudo mysql -u root <<EOF
-CREATE DATABASE glastree CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-CREATE USER 'glastree'@'localhost' IDENTIFIED BY 'ScegliPasswordFortep4ss!';
-GRANT ALL ON glastree.* TO 'glastree'@'localhost';
-FLUSH PRIVILEGES;
-EOF
-
-mysql -u glastree -p glastree < /tmp/restore/database.sql
- -
Passo 6: Configura .env
-
cp /tmp/restore/.env .env
-# Modifica se necessario:
-#   APP_URL=https://nuovo-dominio.it
-#   DB_HOST=localhost
-#   DB_DATABASE=glastree
-#   DB_USERNAME=glastree
-#   DB_PASSWORD=ScegliPasswordFortep4ss!
-
-#  DECIDI SULL'APP_KEY (leggi avviso sopra!)
-#  php artisan key:generate   ← SOLO se non hai il .env originale
- -
Passo 7: Ripristina file e permessi
-
cp -r /tmp/restore/files/* storage/app/documenti/
-
-sudo chown -R www-data:www-data storage bootstrap/cache
-sudo chmod -R 755 storage bootstrap/cache
-
-php artisan storage:link
- -
Passo 8: Cache
-
php artisan optimize:clear
-php artisan config:cache
-php artisan route:cache
-php artisan view:cache
- -
Passo 9: Configura Apache
-
sudo tee /etc/apache2/sites-available/glastree.conf <<APACHE
-<VirtualHost *:80>
-    ServerName glastree.esempio.it
-    DocumentRoot /var/www/glastree/public
-
-    <Directory /var/www/glastree/public>
-        Options -Indexes +FollowSymLinks
-        AllowOverride All
-        Require all granted
-    </Directory>
-
-    ErrorLog \${APACHE_LOG_DIR}/glastree_error.log
-    CustomLog \${APACHE_LOG_DIR}/glastree_access.log combined
-</VirtualHost>
-APACHE
-
-sudo a2dissite 000-default.conf
-sudo a2ensite glastree.conf
-sudo systemctl reload apache2
- -
Passo 10: SSL Let's Encrypt
-
sudo apt install -y certbot python3-certbot-apache
-sudo certbot --apache -d glastree.esempio.it
- -
Passo 11: Cron per backup automatico
-
sudo crontab -u www-data -e
-# Inserisci:
-* * * * * cd /var/www/glastree && php artisan schedule:run >> /dev/null 2>&1
- -
Passo 12: Verifica finale
-
    -
  1. Apri https://glastree.esempio.it nel browser
  2. -
  3. Fai login con le credenziali esistenti
  4. -
  5. Verifica: Dashboard, Documenti, Impostazioni, Email
  6. -
  7. Se hai rigenerato APP_KEY: riconfigura SMTP e OAuth Google Drive
  8. -
- -
- -
Comandi Artisan
-

Per installazione e ripristino usa i comandi Artisan da terminale. Vedi la sezione Installazione per la guida completa.

-
-
-
- - -
-
-
-

Docker

-
-
-
Creare un'immagine Docker con dati di base
-

Puoi creare un'immagine Docker pronta all'uso che include l'applicazione e i dati di base (tipologie documenti, tipologie eventi, ruoli). Scegli la configurazione in base alle tue esigenze:

- -
- - Ottenere il codice: puoi clonare il repository con git clone <URL> glastree oppure, se non hai git, estrarre il file ZIP ricevuto con unzip glastree.zip -d glastree e posizionarti nella cartella glastree prima di procedere. -
- -
-
-
-
SQLite (Leggero)
-

Database embedded, nessun servizio aggiuntivo. Ideale per demo, test, sviluppo locale o ambienti con poca concorrenza.

-
-
-
-
-
MySQL (Standard)
-

Database separato in un container MySQL. Configurazione standard, ideale per produzione, staging e ambienti con piu utenti.

-
-
-
- -
1. Dockerfile (comune a entrambe le modalita)
-

Crea un file Dockerfile nella root del progetto:

-
FROM php:8.4-apache
-
-# Abilita mod_rewrite
-RUN docker-php-ext-enable opcache \
-    && a2enmod rewrite
-
-# Installa estensioni PHP (sia SQLite che MySQL)
-RUN docker-php-ext-install pdo_mysql pdo_sqlite bcmath gd zip
-
-# Installa Composer
-COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
-
-# Configura DocumentRoot per Laravel
-ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
-RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
-    && sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
-
-# Copia l'applicazione
-COPY . /var/www/html/
-
-# Installa dipendenze e compila asset
-RUN composer install --no-dev --optimize-autoloader \
-    && mkdir -p storage/app/public \
-    && mkdir -p storage/framework/cache/data \
-    && mkdir -p storage/framework/sessions \
-    && mkdir -p storage/framework/views \
-    && mkdir -p storage/logs \
-    && mkdir -p bootstrap/cache \
-    && chown -R www-data:www-data storage bootstrap/cache
-
-# Entrypoint per inizializzazione
-COPY docker-entrypoint.sh /usr/local/bin/
-RUN chmod +x /usr/local/bin/docker-entrypoint.sh
-
-ENTRYPOINT ["docker-entrypoint.sh"]
-CMD ["apache2-foreground"]
- -
2. Entrypoint Script (comune)
-

Crea docker-entrypoint.sh. Lo script rileva automaticamente la configurazione in base alle variabili d'ambiente:

-
#!/bin/bash
-set -e
-
-# Se .env non esiste, lo genera dalle variabili d'ambiente
-if [ ! -f .env ]; then
-    cp .env.example .env
-
-    if [ "$DB_CONNECTION" = "mysql" ]; then
-        # Configura MySQL
-        sed -i "s/DB_CONNECTION=mysql/DB_CONNECTION=mysql/" .env
-        sed -i "s/DB_HOST=.*/DB_HOST=${DB_HOST:-mysql}/" .env
-        sed -i "s/DB_PORT=.*/DB_PORT=${DB_PORT:-3306}/" .env
-        sed -i "s/DB_DATABASE=.*/DB_DATABASE=${DB_DATABASE:-glastree}/" .env
-        sed -i "s/DB_USERNAME=.*/DB_USERNAME=${DB_USERNAME:-glastree}/" .env
-        sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=${DB_PASSWORD:-secret}/" .env
-
-        # Attende che MySQL sia pronto
-        echo "Attendo MySQL..."
-        until php -r "new PDO('mysql:host=${DB_HOST:-mysql};dbname=${DB_DATABASE:-glastree}', '${DB_USERNAME:-glastree}', '${DB_PASSWORD:-secret}');" 2>/dev/null; do
-            sleep 2
-        done
-        echo "MySQL pronto."
-    else
-        # Configura SQLite
-        sed -i 's/DB_CONNECTION=mysql/DB_CONNECTION=sqlite/' .env
-        sed -i 's/DB_HOST=.*//' .env
-        sed -i 's/DB_PORT=.*//' .env
-        sed -i 's/DB_DATABASE=.*/DB_DATABASE=\/var\/www\/html\/database\/database.sqlite/' .env
-        sed -i 's/DB_USERNAME=.*//' .env
-        sed -i 's/DB_PASSWORD=.*//' .env
-
-        touch database/database.sqlite
-        chmod 664 database/database.sqlite
-    fi
-
-    # Genera APP_KEY
-    php artisan key:generate --force
-fi
-
-# Esegui migration e seed se il database e vuoto
-if [ ! -f .db_initialized ]; then
-    php artisan migrate --force
-    php artisan db:seed --force
-    touch .db_initialized
-fi
-
-# Configura storage link
-php artisan storage:link --force 2>/dev/null || true
-
-exec "$@"
-
chmod +x docker-entrypoint.sh
- -
3. Seed Base Dati (comune)
-

Per includere tipologie documenti, tipologie eventi e ruoli, crea un seeder dedicato:

-
php artisan make:seeder DockerBaseDataSeeder
-

Contenuto di database/seeders/DockerBaseDataSeeder.php:

-
<?php
-
-declare(strict_types=1);
-
-namespace Database\Seeders;
-
-use Illuminate\Database\Seeder;
-use Illuminate\Support\Facades\DB;
-
-class DockerBaseDataSeeder extends Seeder
-{
-    public function run(): void
-    {
-        // Tipologie Documenti
-        $tipologieDoc = ['documento', 'avatar', 'galleria', 'statuto', 'programma', 'locandina', 'altro'];
-        foreach ($tipologieDoc as $ord => $nome) {
-            DB::table('tipologie_documenti')->updateOrInsert(
-                ['nome' => $nome],
-                ['descrizione' => ucfirst($nome), 'ordine' => $ord + 1, 'attiva' => true]
-            );
-        }
-
-        // Tipologie Eventi
-        $tipologieEventi = [
-            ['nome' => 'catechesi', 'descrizione' => 'Catechesi'],
-            ['nome' => 'liturgia', 'descrizione' => 'Liturgia'],
-            ['nome' => 'animazione', 'descrizione' => 'Animazione'],
-            ['nome' => 'formazione', 'descrizione' => 'Formazione'],
-            ['nome' => 'incontro', 'descrizione' => 'Incontro'],
-            ['nome' => 'riunione', 'descrizione' => 'Riunione'],
-            ['nome' => 'festa', 'descrizione' => 'Festa'],
-            ['nome' => 'altro', 'descrizione' => 'Altro'],
-        ];
-        foreach ($tipologieEventi as $ord => $t) {
-            DB::table('tipologie_eventi')->updateOrInsert(
-                ['nome' => $t['nome']],
-                ['descrizione' => $t['descrizione'], 'ordine' => $ord + 1, 'attiva' => true]
-            );
-        }
-
-        // Ruoli
-        $ruoli = ['presidente', 'vicepresidente', 'segretario', 'tesoriere', 'consigliere', 'volontario', 'socio', 'altro'];
-        foreach ($ruoli as $ord => $nome) {
-            DB::table('ruoli')->updateOrInsert(
-                ['nome' => $nome],
-                ['descrizione' => ucfirst($nome), 'ordine' => $ord + 1, 'attiva' => true]
-            );
-        }
-    }
-}
-

Registralo in database/seeders/DatabaseSeeder.php:

-
$this->call([
-    // ... altri seeder ...
-    DockerBaseDataSeeder::class,
-]);
- -
4. Docker Compose
- -
Opzione A — SQLite (leggero)
-
services:
-  glastree:
-    build: .
-    ports:
-      - "8080:80"
-    volumes:
-      - glastree_storage:/var/www/html/storage
-      - glastree_db:/var/www/html/database
-    environment:
-      - APP_ENV=production
-      - APP_DEBUG=false
-      - APP_URL=http://localhost:8080
-      - DB_CONNECTION=sqlite
-
-volumes:
-  glastree_storage:
-  glastree_db:
- -
Opzione B — MySQL (standard)
-
services:
-  glastree:
-    build: .
-    ports:
-      - "8080:80"
-    volumes:
-      - glastree_storage:/var/www/html/storage
-    depends_on:
-      mysql:
-        condition: service_healthy
-    environment:
-      - APP_ENV=production
-      - APP_DEBUG=false
-      - APP_URL=http://localhost:8080
-      - DB_CONNECTION=mysql
-      - DB_HOST=mysql
-      - DB_PORT=3306
-      - DB_DATABASE=glastree
-      - DB_USERNAME=glastree
-      - DB_PASSWORD=secret
-
-  mysql:
-    image: mysql:8.0
-    volumes:
-      - mysql_data:/var/lib/mysql
-    environment:
-      - MYSQL_DATABASE=glastree
-      - MYSQL_USER=glastree
-      - MYSQL_PASSWORD=secret
-      - MYSQL_ROOT_PASSWORD=root_secret
-    healthcheck:
-      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
-      interval: 5s
-      timeout: 3s
-      retries: 10
-
-volumes:
-  glastree_storage:
-  mysql_data:
- -
5. Build e avvio
-

Assicurati di essere nella cartella del progetto (ottenuta via git clone o estraendo il ZIP), poi:

-
# Costruisci l'immagine (comune)
-docker build -t glastree:latest .
-
-# Avvia con SQLite
-docker compose -f docker-compose.yml up -d
-
-# Oppure avvia con MySQL
-# docker compose -f docker-compose.mysql.yml up -d
-
-# Apri nel browser
-open http://localhost:8080
- -
6. Primo accesso
-

Al primo avvio, l'entrypoint esegue automaticamente migration e seed. Troverai gia popolati:

-
    -
  • Tipologie Documenti: documento, avatar, galleria, statuto, programma, locandina, altro
  • -
  • Tipologie Eventi: catechesi, liturgia, animazione, formazione, incontro, riunione, festa, altro
  • -
  • Ruoli: presidente, vicepresidente, segretario, tesoriere, consigliere, volontario, socio, altro
  • -
-

Dovrai creare il primo utente amministratore via CLI:

-
docker exec -it glastree php artisan tinker --execute="
-\$u = new \App\Models\User;
-\$u->name = 'Amministratore';
-\$u->email = 'admin@esempio.it';
-\$u->password = bcrypt('password-forte');
-\$u->is_admin = true;
-\$u->permissions = ['individui' => 2, 'gruppi' => 2, 'eventi' => 2, 'documenti' => 2, 'mailing' => 2, 'viste' => 2, 'report' => 2, 'settings' => 2];
-\$u->save();
-echo 'Utente creato con successo!';
-"
- -
-
Note importanti
-
    -
  • Persistenza: i volumi Docker preservano storage e database tra i riavvii
  • -
  • APP_KEY: viene generata al primo avvio — se elimini i volumi, la perdi e i dati criptati diventano inaccessibili
  • -
  • MySQL in produzione: imposta password sicure per MYSQL_PASSWORD e MYSQL_ROOT_PASSWORD
  • -
  • File compose separati: puoi mantenere entrambi i file (docker-compose.yml per SQLite, docker-compose.mysql.yml per MySQL) e scegliere con -f
  • -
-
-
-
-
- - -
-
-
-

Guida all'Installazione

-
-
-
Panoramica
-

L'installazione avviene tramite l'interattivo install.php che guida passo-passo. Supporta due modalita:

-
-
-
-
Fresh Install
-

Installa l'applicazione da zero su un nuovo server: crea il database, esegue le migration, popola i dati di base e crea l'amministratore.

-
-
-
-
-
Restore da Backup
-

Ripristina un'installazione esistente da un file ZIP di backup: importa il database, ripristina i documenti e la configurazione.

-
-
-
- -
Requisiti del Server
- - - - - - - - - -
ComponenteVersione MinimaNote
Web ServerApache 2.4+Con mod_rewrite abilitato
PHP8.2+ (consigliato 8.4)Estensioni: pdo_mysql, mbstring, xml, curl, zip, gd, fileinfo
MySQL / MariaDBMySQL 8.0+ / MariaDB 10.5+Supporto utf8mb4
Composer2.xPer gestione dipendenze PHP
Node.js / npmNode 20+ / npm 10+Per compilazione asset frontend (opzionale se precompilati)
- -
Installazione Passo-Passo
- -
Passo 1: Preparare il server LAMP
-
sudo apt update && sudo apt upgrade -y
-
-sudo apt install -y apache2 mariadb-server php8.4 php8.4-cli \
-  php8.4-mysql php8.4-xml php8.4-mbstring php8.4-curl \
-  php8.4-zip php8.4-bcmath php8.4-gd php8.4-intl \
-  composer git unzip
-
-sudo a2enmod rewrite
-sudo systemctl restart apache2
- -
Passo 2: Ottenere l'applicazione
-
- - Puoi clonare il repository con git oppure estrarre il file ZIP ricevuto nella cartella /var/www/glastree. -
-
cd /var/www
-
-# Opzione A — Git clone
-git clone <URL_REPOSITORY> glastree
-
-# Opzione B — ZIP (se non hai git)
-# unzip /percorso/del/glastree.zip -d glastree
-
-cd glastree
- -
Passo 3: Eseguire l'installer
-

Lancerai l'installer interattivo che ti guidera attraverso tutte le fasi:

-
php install.php
-

L'installer ti chiedera:

-
    -
  1. Modalità: Fresh Install (Apache/Docker) o Restore da Backup
  2. -
  3. Parametri generali: nome sito, amministratore (nome, email, password), URL pubblico
  4. -
  5. Database: MySQL (host, porta, nome, utente, password) o SQLite
  6. -
-

L'installer esegue automaticamente:

-
    -
  • Generazione .env e APP_KEY
  • -
  • Creazione del database
  • -
  • composer install e registrazione pacchetti
  • -
  • Migration e seed dei dati di base
  • -
  • Creazione dell'utente amministratore
  • -
  • Compilazione asset frontend (se npm disponibile)
  • -
  • Impostazione permessi cartelle
  • -
-
-
Docker
-

Se scegli la modalita Docker, l'installer builda l'immagine, avvia i container e crea l'admin all'interno del container.

-
-
-
Restore da Backup
-

Se scegli Restore, l'installer ti chiedera il percorso del file ZIP di backup, ripristinera il database, i file e la configurazione.

-
- -
Passo 4: Configurare Apache (solo modalita Fresh Install)
-
sudo tee /etc/apache2/sites-available/glastree.conf <<APACHE
-<VirtualHost *:80>
-    ServerName glastree.esempio.it
-    DocumentRoot /var/www/glastree/public
-
-    <Directory /var/www/glastree/public>
-        Options -Indexes +FollowSymLinks
-        AllowOverride All
-        Require all granted
-    </Directory>
-
-    ErrorLog \${APACHE_LOG_DIR}/glastree_error.log
-    CustomLog \${APACHE_LOG_DIR}/glastree_access.log combined
-</VirtualHost>
-APACHE
-
-sudo a2dissite 000-default.conf
-sudo a2ensite glastree.conf
-sudo systemctl reload apache2
- - Importante: Il restore da backup richiede che tu abbia un file ZIP generato dalla pagina Admin → Backup del server originale. Estrai manualmente il contenuto seguendo la struttura del progetto. -
- -
Cosa succede durante l'installazione
-

I comandi php artisan migrate --seed eseguono:

-
    -
  1. Genera APP_KEY per la crittografia (gia eseguito al passo 5)
  2. -
  3. Esegue tutte le migration per creare le tabelle del database
  4. -
  5. Popola i dati di base (diocesi, comuni, ruoli, preset)
  6. -
  7. Crea il collegamento storage → public/storage
  8. -
  9. Crea l'utente amministratore con i permessi completi
  10. -
- -
Restore da Backup
-

Il backup ZIP generato dalla pagina Admin → Backup contiene un dump SQL e i file dei documenti. Per ripristinare:

-
    -
  • Estrai il file ZIP in una cartella temporanea
  • -
  • Importa il database dal file SQL (mysql -u root -p glastree < backup/database.sql)
  • -
  • Copia i file in storage/app/ per ripristinare i documenti
  • -
  • Copia il file .env dal backup (modifica le credenziali DB per il nuovo server)
  • -
  • Esegui php artisan key:generate se la APP_KEY del backup non è utilizzabile
  • -
- -
Dopo l'Installazione
-
    -
  1. Configura SSL con Let's Encrypt: -
    sudo apt install -y certbot python3-certbot-apache
    -sudo certbot --apache -d glastree.esempio.it
    -
  2. -
  3. Accedi con le credenziali amministratore create durante l'installazione
  4. -
  5. Configura l'applicazione in Impostazioni: -
      -
    • Nome applicazione e logo
    • -
    • Email (SMTP per invio, IMAP per ricezione)
    • -
    • Repository remoti (Google Drive, Nextcloud)
    • -
    -
  6. -
  7. Crea utenti dal pannello Admin → Utenti
  8. -
  9. Configura il cron per backup automatico e sync email: -
    sudo crontab -u www-data -e
    -# Inserisci:
    -* * * * * cd /var/www/glastree && php artisan schedule:run >> /dev/null 2>&1
    -
  10. -
- -
Risoluzione Problemi
-
-
Errore "500 | Server Error" dopo l'installazione
-

Probabilmente mancano permessi sulle cartelle storage o bootstrap/cache:

-
sudo chown -R www-data:www-data storage bootstrap/cache
-sudo chmod -R 775 storage bootstrap/cache
-
-
-
Errore "No application encryption key"
-

APP_KEY non generata. Nella cartella dell'app:

-
php artisan key:generate
-
-
-
mod_rewrite non funziona
-

Se le rotte restituiscono 404, verifica che Apache abbia AllowOverride:

-
sudo a2enmod rewrite
-# Nel VirtualHost: AllowOverride All
-sudo systemctl reload apache2
-
-
-
-
-
-
-
- - -stopSection(); ?> - -make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?> \ No newline at end of file diff --git a/tests/Feature/EmailSaveTest.php b/tests/Feature/EmailSaveTest.php new file mode 100644 index 00000000..76faa21a --- /dev/null +++ b/tests/Feature/EmailSaveTest.php @@ -0,0 +1,28 @@ +delete(); +}); + +it('saves email settings via POST form', function () { + $user = User::first(); + $response = $this->actingAs($user)->post(route('impostazioni.email.save'), [ + 'imap_host' => 'test.feature', + 'imap_port' => '993', + 'imap_encryption' => 'ssl', + 'imap_username' => 'featureuser', + 'imap_password' => 'featurepass', + 'email_address' => 'feature@test.com', + 'email_name' => 'Feature Test', + 'is_active' => '1', + ]); + + $response->assertSessionHas('success'); + + $record = EmailSetting::where('imap_host', 'test.feature')->first(); + expect($record)->not->toBeNull(); + expect($record->email_address)->toBe('feature@test.com'); +}); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 89cb91ad..8bb607ad 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir); return array( 'App\\Console\\Commands\\BackupRunCommand' => $baseDir . '/app/Console/Commands/BackupRunCommand.php', + 'App\\Console\\Commands\\DiagnoseEmail' => $baseDir . '/app/Console/Commands/DiagnoseEmail.php', 'App\\Console\\Commands\\ExportHelpPdf' => $baseDir . '/app/Console/Commands/ExportHelpPdf.php', 'App\\Console\\Commands\\ResetUserPassword' => $baseDir . '/app/Console/Commands/ResetUserPassword.php', 'App\\Console\\Commands\\SyncUserPermissions' => $baseDir . '/app/Console/Commands/SyncUserPermissions.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 222531c5..ee022808 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -619,6 +619,7 @@ class ComposerStaticInit74199c0a3889e8d1256a25f93805ef56 public static $classMap = array ( 'App\\Console\\Commands\\BackupRunCommand' => __DIR__ . '/../..' . '/app/Console/Commands/BackupRunCommand.php', + 'App\\Console\\Commands\\DiagnoseEmail' => __DIR__ . '/../..' . '/app/Console/Commands/DiagnoseEmail.php', 'App\\Console\\Commands\\ExportHelpPdf' => __DIR__ . '/../..' . '/app/Console/Commands/ExportHelpPdf.php', 'App\\Console\\Commands\\ResetUserPassword' => __DIR__ . '/../..' . '/app/Console/Commands/ResetUserPassword.php', 'App\\Console\\Commands\\SyncUserPermissions' => __DIR__ . '/../..' . '/app/Console/Commands/SyncUserPermissions.php', diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 7f2a72d3..69eada89 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'laravel/laravel', 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => '469e8c014fba82f598245b5a76fba8e1209828c8', + 'reference' => 'cbe3470c8c6202f5f7091777692490fb074b0af9', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -427,7 +427,7 @@ 'laravel/laravel' => array( 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => '469e8c014fba82f598245b5a76fba8e1209828c8', + 'reference' => 'cbe3470c8c6202f5f7091777692490fb074b0af9', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(),