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>
124 lines
4.0 KiB
PHP
124 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Setting;
|
|
use App\Models\User;
|
|
use Database\Seeders\RolesAndPermissionsSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Cambio password: la password attuale si chiede a chi cambia di sua
|
|
* iniziativa, e cambiare la password chiude le sessioni aperte altrove.
|
|
*/
|
|
class CambioPasswordTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->withoutVite();
|
|
$this->seed(RolesAndPermissionsSeeder::class);
|
|
Setting::firstOrCreate([], ['congregazione_nome' => 'Congregazione di prova']);
|
|
}
|
|
|
|
private function utente(bool $obbligato = false): User
|
|
{
|
|
$utente = User::create([
|
|
'name' => 'Mario Rossi',
|
|
'email' => 'mario@example.test',
|
|
'password' => 'vecchia-password',
|
|
]);
|
|
$utente->forceFill(['password_change_required' => $obbligato])->save();
|
|
$utente->assignRole('operatore');
|
|
|
|
return $utente;
|
|
}
|
|
|
|
public function test_chi_cambia_di_sua_iniziativa_deve_dare_la_password_attuale(): void
|
|
{
|
|
$utente = $this->utente();
|
|
|
|
$this->actingAs($utente)
|
|
->post(route('password.change.store'), [
|
|
'password' => 'nuova-password-1',
|
|
'password_confirmation' => 'nuova-password-1',
|
|
])
|
|
->assertSessionHasErrors('current_password');
|
|
|
|
$this->actingAs($utente)
|
|
->post(route('password.change.store'), [
|
|
'current_password' => 'sbagliata',
|
|
'password' => 'nuova-password-1',
|
|
'password_confirmation' => 'nuova-password-1',
|
|
])
|
|
->assertSessionHasErrors('current_password');
|
|
|
|
$this->assertTrue(Hash::check('vecchia-password', $utente->fresh()->password));
|
|
|
|
$this->actingAs($utente)
|
|
->post(route('password.change.store'), [
|
|
'current_password' => 'vecchia-password',
|
|
'password' => 'nuova-password-1',
|
|
'password_confirmation' => 'nuova-password-1',
|
|
])
|
|
->assertRedirect(route('dashboard'));
|
|
|
|
$this->assertTrue(Hash::check('nuova-password-1', $utente->fresh()->password));
|
|
}
|
|
|
|
public function test_dopo_un_ripristino_la_password_attuale_non_si_chiede(): void
|
|
{
|
|
$utente = $this->utente(obbligato: true);
|
|
|
|
$this->actingAs($utente)
|
|
->get(route('password.change'))
|
|
->assertOk()
|
|
->assertDontSee('name="current_password"', false);
|
|
|
|
$this->actingAs($utente)
|
|
->post(route('password.change.store'), [
|
|
'password' => 'nuova-password-1',
|
|
'password_confirmation' => 'nuova-password-1',
|
|
])
|
|
->assertRedirect(route('dashboard'));
|
|
|
|
$this->assertFalse((bool) $utente->fresh()->password_change_required);
|
|
}
|
|
|
|
public function test_una_sessione_aperta_altrove_si_chiude_quando_cambia_la_password(): void
|
|
{
|
|
$utente = $this->utente();
|
|
$hashVecchio = $utente->password;
|
|
|
|
// La sessione "altrove" ha registrato l'impronta della password di allora.
|
|
$utente->update(['password' => 'cambiata-da-un-altra-parte']);
|
|
|
|
$this->actingAs($utente)
|
|
->withSession(['password_hash_web' => $hashVecchio])
|
|
->get(route('dashboard'))
|
|
->assertRedirect(route('login'));
|
|
|
|
$this->assertGuest();
|
|
}
|
|
|
|
public function test_la_sessione_che_cambia_la_password_resta_aperta(): void
|
|
{
|
|
$utente = $this->utente();
|
|
|
|
$this->actingAs($utente)
|
|
->withSession(['password_hash_web' => $utente->password])
|
|
->post(route('password.change.store'), [
|
|
'current_password' => 'vecchia-password',
|
|
'password' => 'nuova-password-1',
|
|
'password_confirmation' => 'nuova-password-1',
|
|
])
|
|
->assertRedirect(route('dashboard'));
|
|
|
|
$this->get(route('dashboard'))->assertOk();
|
|
}
|
|
}
|