Blocco 2 - Esiti delle azioni Livewire come avvisi (trait Avvisa) invece di flash che comparivano alla pagina dopo. - PDF, miniature e versioni dei territori non più serviti da nginx su /storage: TerritorioFileController con login, permessi e cache privata. - Ripristino tutto o niente: verifica dell'archivio, una transazione con import, piantine, blocco account e scambio dei file annullabile. - Backup formato 2 con piantine, storico PDF e area KML. - Posto unico preso in un passo (Cache::lock) e rispettato anche da import XML e PDF. - Import PDF da cartella: abbinamento corretto (1-A, 12 B, ambigui), caricamento a lotti, file non PDF ignorati, PDF sostituito nello storico. - L'import XML elimina i file dei territori che non usa più; comando territori:file-orfani per quelli accumulati prima. Blocco 3 - Password attuale richiesta al cambio volontario; AuthenticateSession chiude le sessioni aperte altrove. - Niente nomi dei proclamatori in chiaro nel registro attività. - Export XML senza remember_token; chi riceve l'hash dal file deve cambiare password. - Campagne: ultimo giorno incluso, percentuale sui territori distinti. - Coda: retry_after 960 s, stop_grace_period 16m, Redis volatile-lru, impostazioni rilette a ogni job. - Azzeramento che cancella anche piantine, area KML e anteprime. - Pulsanti profilo e menu che non si nascondevano; icona del sito. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
96 lines
4.2 KiB
PHP
96 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Auth;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Jobs\RestoreBackupArchive;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Validation\Rules\Password;
|
|
|
|
/**
|
|
* Cambio password obbligatorio, imposto dopo il ripristino di un backup.
|
|
*
|
|
* Volutamente NON e' un componente Livewire: la pagina deve restare
|
|
* raggiungibile mentre RequirePasswordChange respinge tutto il resto, incluse
|
|
* le richieste /livewire/update. Due rotte HTTP normali sono banali da
|
|
* escludere; distinguere quale componente sta dietro una POST di Livewire no.
|
|
*/
|
|
class PasswordChangeController extends Controller
|
|
{
|
|
public function show()
|
|
{
|
|
$user = auth()->user();
|
|
|
|
return view('auth.password-change', [
|
|
'user' => $user,
|
|
// Chi arriva qui spontaneamente (dal profilo) puo' tornare indietro;
|
|
// chi e' stato dirottato dal middleware no.
|
|
'forced' => (bool) $user->password_change_required,
|
|
// Il ripristino gira in coda e non ha una sessione in cui lasciare
|
|
// un flash; deposita l'esito in cache a nome di chi l'ha avviato e
|
|
// lo si legge qui, che e' la prima pagina che quella persona vede.
|
|
//
|
|
// Si legge senza consumare, e si cancella solo a password cambiata.
|
|
// Con un pull, il messaggio non arriverebbe mai a schermo: quando e'
|
|
// il middleware a dirottare una richiesta di Livewire, il client
|
|
// segue il 302 via fetch — ed e' quella fetch a bruciare il
|
|
// messaggio — per poi rifare la stessa GET con window.location, che
|
|
// troverebbe la cache gia' vuota.
|
|
'esitoRipristino' => Cache::get(RestoreBackupArchive::CHIAVE_ESITO . $user->id),
|
|
]);
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$user = $request->user();
|
|
|
|
// La password attuale si chiede solo a chi arriva qui di sua
|
|
// iniziativa, come fa il profilo.
|
|
//
|
|
// Dopo un ripristino no: gli hash sono quelli del backup, e la
|
|
// "password attuale" di un account e' quella che aveva all'epoca, che
|
|
// l'utente puo' benissimo non ricordare. Chiederla bloccherebbe fuori
|
|
// proprio le persone che questa schermata deve sbloccare; la garanzia li'
|
|
// e' la sessione. Fuori da quel caso, invece, bastava una sessione
|
|
// lasciata aperta per cambiare la password a qualcun altro e chiuderlo
|
|
// fuori dal suo account.
|
|
$regole = ['password' => ['required', 'confirmed', Password::min(8)]];
|
|
if (! $user->password_change_required) {
|
|
$regole['current_password'] = ['required', 'current_password'];
|
|
}
|
|
|
|
$validated = $request->validate($regole, [
|
|
'password.required' => 'Inserisci la nuova password.',
|
|
'password.confirmed' => 'Le due password non coincidono.',
|
|
'current_password.required' => 'Inserisci la password attuale.',
|
|
'current_password.current_password' => 'La password attuale non è corretta.',
|
|
]);
|
|
|
|
// Il cast `hashed` sul modello cifra il valore al salvataggio.
|
|
$user->update([
|
|
'password' => $validated['password'],
|
|
'password_change_required' => false,
|
|
]);
|
|
|
|
// La sessione corrente sopravvive al cambio, le altre no: dopo un
|
|
// ripristino le vecchie credenziali sono da considerarsi compromesse e
|
|
// una sessione aperta altrove lo e' altrettanto. Le altre le chiude
|
|
// AuthenticateSession (bootstrap/app.php) alla loro prossima richiesta,
|
|
// perche' l'hash della password e' cambiato; qui si cambia l'id di
|
|
// questa e si invalida il "ricordami".
|
|
$request->session()->regenerate();
|
|
$user->setRememberToken(null);
|
|
$user->save();
|
|
|
|
// L'esito del ripristino ha esaurito il suo scopo: e' stato letto, e la
|
|
// password richiesta e' stata impostata.
|
|
Cache::forget(RestoreBackupArchive::CHIAVE_ESITO . $user->id);
|
|
|
|
activity()->causedBy($user)->log('password changed');
|
|
|
|
return redirect()->route('dashboard')
|
|
->with('success', 'Password aggiornata. Da ora accedi con quella nuova.');
|
|
}
|
|
}
|