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>
244 lines
9.1 KiB
PHP
244 lines
9.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Piantine\PiantineManager;
|
|
use App\Models\Setting;
|
|
use App\Models\Territorio;
|
|
use App\Models\TerritorioMappa;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Livewire\Livewire;
|
|
use Spatie\Permission\Models\Role;
|
|
use Spatie\Permission\PermissionRegistrar;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* La pagina di gestione delle piantine: accesso riservato, area della città,
|
|
* stato di ogni piantina con ricerca e filtri, pubblicazione e storico.
|
|
*/
|
|
class PiantineManagerTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->withoutVite();
|
|
Storage::fake('public');
|
|
Storage::fake('local');
|
|
}
|
|
|
|
public function test_la_pagina_e_riservata_all_amministratore(): void
|
|
{
|
|
Role::findOr('utente', fn () => Role::create(['name' => 'utente', 'guard_name' => 'web']));
|
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
|
|
|
$utente = User::create([
|
|
'name' => 'Utente semplice',
|
|
'email' => 'utente@example.test',
|
|
'password' => 'password-di-prova',
|
|
]);
|
|
$utente->assignRole('utente');
|
|
|
|
$this->actingAs($utente)->get(route('piantine.index'))->assertForbidden();
|
|
// Due utenti nella stessa sessione: AuthenticateSession butterebbe fuori il secondo.
|
|
$this->flushSession();
|
|
$this->actingAs($this->admin())->get(route('piantine.index'))->assertOk();
|
|
}
|
|
|
|
public function test_il_kml_caricato_diventa_l_area_attiva(): void
|
|
{
|
|
$kml = <<<'XML'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<kml xmlns="http://www.opengis.net/kml/2.2"><Document><Placemark>
|
|
<name>Area</name>
|
|
<Polygon><outerBoundaryIs><LinearRing>
|
|
<coordinates>13.35,38.11 13.37,38.11 13.37,38.13 13.35,38.11</coordinates>
|
|
</LinearRing></outerBoundaryIs></Polygon>
|
|
</Placemark></Document></kml>
|
|
XML;
|
|
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->set('kmlFile', UploadedFile::fake()->createWithContent('citta.kml', $kml))
|
|
->call('caricaKml')
|
|
->assertHasNoErrors();
|
|
|
|
Storage::disk('local')->assertExists('piantine/area.geojson');
|
|
}
|
|
|
|
public function test_un_file_che_non_e_kml_viene_rifiutato(): void
|
|
{
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->set('kmlFile', UploadedFile::fake()->createWithContent('foto.png', 'binario'))
|
|
->call('caricaKml')
|
|
->assertHasErrors('kmlFile');
|
|
}
|
|
|
|
/**
|
|
* La cascata di prima si portava via il disegno insieme al territorio — e
|
|
* l'import XML svuota `territori` in blocco a ogni ripristino.
|
|
*/
|
|
public function test_cancellare_il_territorio_lascia_in_piedi_la_piantina(): void
|
|
{
|
|
$territorio = Territorio::create(['numero' => '12', 'attivo' => true]);
|
|
$mappa = $this->piantina(['territorio_id' => $territorio->id]);
|
|
|
|
$territorio->forceDelete();
|
|
|
|
$this->assertDatabaseCount('territorio_mappe', 1);
|
|
$this->assertNull($mappa->fresh()->territorio_id);
|
|
}
|
|
|
|
public function test_l_elenco_mostra_lo_stato_di_ogni_piantina(): void
|
|
{
|
|
[$territorio, $pubblicata] = $this->pubblicata('7');
|
|
$this->piantina(['nome' => 'Zona porto']);
|
|
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->assertSee('Terr. 7')
|
|
->assertSee('Zona porto')
|
|
->assertSee('Pubblicata')
|
|
->assertSee('Bozza')
|
|
->assertSee('Scollegata');
|
|
}
|
|
|
|
public function test_i_filtri_separano_bozze_pubblicate_e_da_pubblicare(): void
|
|
{
|
|
[, $pubblicata] = $this->pubblicata('7');
|
|
[$t8, $modificata] = $this->pubblicata('8');
|
|
$t8->update(['confini' => 'cambiati dopo la pubblicazione']);
|
|
$this->piantina(['nome' => 'Zona porto']);
|
|
|
|
$componente = Livewire::actingAs($this->admin())->test(PiantineManager::class);
|
|
|
|
$componente->set('filtro', 'pubblicate')
|
|
->assertViewHas('elenco', fn ($e) => $e->pluck('id')->all() === [$pubblicata->id]);
|
|
|
|
$componente->set('filtro', 'da-pubblicare')
|
|
->assertViewHas('elenco', fn ($e) => $e->pluck('id')->all() === [$modificata->id]);
|
|
|
|
$componente->set('filtro', 'scollegate')
|
|
->assertViewHas('elenco', fn ($e) => $e->count() === 1 && $e->first()->nome === 'Zona porto');
|
|
|
|
$componente->set('filtro', 'inventato')
|
|
->assertSet('filtro', 'tutte')
|
|
->assertViewHas('elenco', fn ($e) => $e->count() === 3);
|
|
}
|
|
|
|
public function test_la_ricerca_trova_numero_nome_e_zona(): void
|
|
{
|
|
$zona = \App\Models\Zona::create(['nome' => 'Litorale', 'attivo' => true]);
|
|
$territorio = Territorio::create(['numero' => '12', 'attivo' => true, 'zona_id' => $zona->id]);
|
|
$this->piantina(['territorio_id' => $territorio->id]);
|
|
$this->piantina(['nome' => 'Zona porto']);
|
|
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->set('cerca', 'litor')
|
|
->assertViewHas('elenco', fn ($e) => $e->count() === 1 && $e->first()->territorio_id === $territorio->id)
|
|
->set('cerca', 'PORTO')
|
|
->assertViewHas('elenco', fn ($e) => $e->count() === 1 && $e->first()->nome === 'Zona porto');
|
|
}
|
|
|
|
public function test_pubblica_apre_la_finestra_condivisa_solo_se_si_puo(): void
|
|
{
|
|
$territorio = Territorio::create(['numero' => '12', 'attivo' => true]);
|
|
$collegata = $this->piantina(['territorio_id' => $territorio->id]);
|
|
$scollegata = $this->piantina(['nome' => 'Zona porto']);
|
|
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->call('pubblica', $collegata->id)
|
|
->assertDispatchedTo(\App\Livewire\Piantine\Pubblicazione::class, 'pubblica-piantina', mappaId: $collegata->id);
|
|
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->call('pubblica', $scollegata->id)
|
|
->assertNotDispatched('pubblica-piantina')
|
|
->assertDispatched('avviso');
|
|
}
|
|
|
|
public function test_eliminare_toglie_la_piantina_ma_non_il_territorio(): void
|
|
{
|
|
$territorio = Territorio::create(['numero' => '12', 'attivo' => true]);
|
|
$mappa = $this->piantina(['territorio_id' => $territorio->id]);
|
|
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->call('elimina', $mappa->id)
|
|
->assertDispatched('avviso');
|
|
|
|
$this->assertDatabaseCount('territorio_mappe', 0);
|
|
$this->assertNotNull($territorio->fresh());
|
|
}
|
|
|
|
public function test_ripristinare_una_versione_riporta_la_piantina_da_pubblicare(): void
|
|
{
|
|
[$territorio, $mappa] = $this->pubblicata('7');
|
|
|
|
Storage::disk('public')->put('territori-pdf-versioni/vecchia.pdf', '%PDF-vecchia');
|
|
$versione = \App\Models\TerritorioPdfVersione::create([
|
|
'territorio_id' => $territorio->id,
|
|
'pdf_path' => 'territori-pdf-versioni/vecchia.pdf',
|
|
'origine' => 'piantine',
|
|
'sostituito_il' => now()->subDay(),
|
|
]);
|
|
|
|
Livewire::actingAs($this->admin())
|
|
->test(PiantineManager::class)
|
|
->call('ripristinaVersione', $versione->id)
|
|
->assertDispatched('avviso');
|
|
|
|
$this->assertStringStartsWith('territori-pdf/ripristino-', $territorio->fresh()->pdf_path);
|
|
$this->assertSame(TerritorioMappa::STATO_MODIFICATA, $mappa->fresh()->stato());
|
|
}
|
|
|
|
/** Una piantina collegata e segnata come pubblicata, senza passare dal renderer. */
|
|
private function pubblicata(string $numero): array
|
|
{
|
|
$territorio = Territorio::create(['numero' => $numero, 'attivo' => true]);
|
|
$pdf = 'territori-pdf/piantina-' . $territorio->id . '-20261001-120000.pdf';
|
|
Storage::disk('public')->put($pdf, '%PDF-piantina');
|
|
$territorio->update(['pdf_path' => $pdf]);
|
|
|
|
$mappa = $this->piantina(['territorio_id' => $territorio->id]);
|
|
$mappa->load('territorio.zona');
|
|
$mappa->update([
|
|
'geojson_pubblicato' => $mappa->geojson,
|
|
'impronta_pubblicata' => $mappa->impronta(),
|
|
'pubblicata_at' => now(),
|
|
]);
|
|
|
|
return [$territorio, $mappa->fresh()];
|
|
}
|
|
|
|
private function piantina(array $valori = []): TerritorioMappa
|
|
{
|
|
return TerritorioMappa::create(array_merge([
|
|
'geojson' => '{"type":"Polygon","coordinates":[[[13.35,38.11],[13.37,38.11],[13.37,38.13],[13.35,38.11]]]}',
|
|
], $valori));
|
|
}
|
|
|
|
private function admin(): User
|
|
{
|
|
Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']);
|
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
|
|
|
Setting::firstOrCreate([], ['congregazione_nome' => 'Congregazione di prova']);
|
|
|
|
$utente = User::firstOrCreate(
|
|
['email' => 'admin@example.test'],
|
|
['name' => 'Amministratore', 'password' => 'password-di-prova'],
|
|
);
|
|
$utente->assignRole('amministratore');
|
|
|
|
return $utente;
|
|
}
|
|
}
|