Editor piantine: bozza automatica e pubblicazione con anteprima
- Il disegno è bozza e si salva da solo; i dati del territorio si modificano dall'editor e valgono subito nel gestionale. - Un solo "Pubblica" (immagine + PDF), uguale in editor e gestione: anteprima preparata in coda su disco privato, conferma obbligatoria, rifiutata se nel frattempo è cambiato qualcosa di stampato. - Stati Bozza / Pubblicata / Modifiche da pubblicare, calcolati sull'impronta di confine e dati stampati e sul PDF in uso. - Gestione riscritta: stato, ricerca, filtri, storico paginato. - Editor ridisegnato a tre zone, utilizzabile anche su tablet e telefono. - Avvisi via evento (trait Avvisa + <x-avvisi>). - .gitattributes: script shell sempre LF, altrimenti il container locale su Windows non parte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,7 @@ use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* La pagina di gestione delle piantine: accesso riservato, area della città,
|
||||
* e il legame — che si può fare e disfare — fra una piantina e un territorio.
|
||||
* stato di ogni piantina con ricerca e filtri, pubblicazione e storico.
|
||||
*/
|
||||
class PiantineManagerTest extends TestCase
|
||||
{
|
||||
@@ -77,50 +77,6 @@ XML;
|
||||
->assertHasErrors('kmlFile');
|
||||
}
|
||||
|
||||
public function test_una_piantina_si_collega_a_un_territorio(): void
|
||||
{
|
||||
$territorio = Territorio::create(['numero' => '12', 'attivo' => true]);
|
||||
$mappa = $this->piantina(['nome' => 'Zona porto']);
|
||||
|
||||
Livewire::actingAs($this->admin())
|
||||
->test(PiantineManager::class)
|
||||
->call('apriCollegamento', $mappa->id)
|
||||
->set('territorioDaCollegare', $territorio->id)
|
||||
->call('collega', $mappa->id);
|
||||
|
||||
$this->assertSame($territorio->id, $mappa->fresh()->territorio_id);
|
||||
}
|
||||
|
||||
public function test_un_territorio_che_ha_gia_una_piantina_non_ne_accetta_una_seconda(): void
|
||||
{
|
||||
$territorio = Territorio::create(['numero' => '12', 'attivo' => true]);
|
||||
$this->piantina(['territorio_id' => $territorio->id]);
|
||||
$seconda = $this->piantina(['nome' => 'Doppione']);
|
||||
|
||||
Livewire::actingAs($this->admin())
|
||||
->test(PiantineManager::class)
|
||||
->call('apriCollegamento', $seconda->id)
|
||||
->set('territorioDaCollegare', $territorio->id)
|
||||
->call('collega', $seconda->id);
|
||||
|
||||
$this->assertNull($seconda->fresh()->territorio_id);
|
||||
}
|
||||
|
||||
public function test_scollegare_conserva_la_piantina_e_le_da_un_nome(): void
|
||||
{
|
||||
$territorio = Territorio::create(['numero' => '12', 'attivo' => true]);
|
||||
$mappa = $this->piantina(['territorio_id' => $territorio->id]);
|
||||
|
||||
Livewire::actingAs($this->admin())
|
||||
->test(PiantineManager::class)
|
||||
->call('scollega', $mappa->id);
|
||||
|
||||
$mappa->refresh();
|
||||
$this->assertNull($mappa->territorio_id);
|
||||
$this->assertSame('Ex territorio 12', $mappa->nome);
|
||||
$this->assertDatabaseCount('territorio_mappe', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* La cascata di prima si portava via il disegno insieme al territorio — e
|
||||
* l'import XML svuota `territori` in blocco a ogni ripristino.
|
||||
@@ -136,52 +92,128 @@ XML;
|
||||
$this->assertNull($mappa->fresh()->territorio_id);
|
||||
}
|
||||
|
||||
public function test_senza_territorio_il_pdf_non_si_genera(): void
|
||||
public function test_l_elenco_mostra_lo_stato_di_ogni_piantina(): void
|
||||
{
|
||||
$mappa = $this->piantina(['nome' => 'Zona porto']);
|
||||
[$territorio, $pubblicata] = $this->pubblicata('7');
|
||||
$this->piantina(['nome' => 'Zona porto']);
|
||||
|
||||
Livewire::actingAs($this->admin())
|
||||
->test(PiantineManager::class)
|
||||
->call('generaPdf', $mappa->id);
|
||||
|
||||
$this->assertDatabaseCount('territorio_pdf_versioni', 0);
|
||||
->assertSee('Terr. 7')
|
||||
->assertSee('Zona porto')
|
||||
->assertSee('Pubblicata')
|
||||
->assertSee('Bozza')
|
||||
->assertSee('Scollegata');
|
||||
}
|
||||
|
||||
/**
|
||||
* L'anteprima serve a guardare la cartolina PRIMA di mandarla in vigore:
|
||||
* se toccasse pdf_path o lo storico, non sarebbe un'anteprima.
|
||||
*/
|
||||
public function test_l_anteprima_mostra_il_pdf_senza_sostituire_niente(): void
|
||||
public function test_i_filtri_separano_bozze_pubblicate_e_da_pubblicare(): void
|
||||
{
|
||||
$territorio = Territorio::create(['numero' => '7', 'attivo' => true, 'confini' => 'Nord: via Roma']);
|
||||
$mappa = $this->piantina([
|
||||
[, $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,
|
||||
'image_path' => 'territori-mappe/piantina-prova.png',
|
||||
'pdf_path' => 'territori-pdf-versioni/vecchia.pdf',
|
||||
'origine' => 'piantine',
|
||||
'sostituito_il' => now()->subDay(),
|
||||
]);
|
||||
|
||||
$immagine = imagecreatetruecolor(80, 50);
|
||||
ob_start();
|
||||
imagepng($immagine);
|
||||
Storage::disk('public')->put($mappa->image_path, ob_get_clean());
|
||||
imagedestroy($immagine);
|
||||
Livewire::actingAs($this->admin())
|
||||
->test(PiantineManager::class)
|
||||
->call('ripristinaVersione', $versione->id)
|
||||
->assertDispatched('avviso');
|
||||
|
||||
$risposta = $this->actingAs($this->admin())->get(route('piantine.anteprima', $mappa));
|
||||
|
||||
$risposta->assertOk();
|
||||
$risposta->assertHeader('Content-Type', 'application/pdf');
|
||||
$this->assertStringStartsWith('%PDF', $risposta->getContent());
|
||||
|
||||
$this->assertNull($territorio->fresh()->pdf_path);
|
||||
$this->assertSame(0, \App\Models\TerritorioPdfVersione::count());
|
||||
$this->assertStringStartsWith('territori-pdf/ripristino-', $territorio->fresh()->pdf_path);
|
||||
$this->assertSame(TerritorioMappa::STATO_MODIFICATA, $mappa->fresh()->stato());
|
||||
}
|
||||
|
||||
public function test_l_anteprima_di_una_piantina_scollegata_non_esiste(): void
|
||||
/** Una piantina collegata e segnata come pubblicata, senza passare dal renderer. */
|
||||
private function pubblicata(string $numero): array
|
||||
{
|
||||
$mappa = $this->piantina(['nome' => 'Scollegata']);
|
||||
$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]);
|
||||
|
||||
$this->actingAs($this->admin())
|
||||
->get(route('piantine.anteprima', $mappa))
|
||||
->assertNotFound();
|
||||
$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
|
||||
@@ -193,7 +225,7 @@ XML;
|
||||
|
||||
private function admin(): User
|
||||
{
|
||||
Role::findOr('amministratore', fn () => Role::create(['name' => 'amministratore', 'guard_name' => 'web']));
|
||||
Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']);
|
||||
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||
|
||||
Setting::firstOrCreate([], ['congregazione_nome' => 'Congregazione di prova']);
|
||||
|
||||
Reference in New Issue
Block a user