Piantine pubblicate anche dopo un ripristino; posto unico senza gare
- Lo stato "Pubblicata" non dipende più dall'id del territorio, che il ripristino ricrea: l'impronta usa il numero, e la piantina ricorda il percorso del PDF pubblicato (pdf_pubblicato, con migrazione che riconosce le piantine già pubblicate). - BackupOperationState: corrente() in sola lettura e liberaCorrente() sotto lo stesso mutex di occupa(), così una lettura non cancella il puntatore di un'operazione appena avviata. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ class TerritorioMappa extends Model
|
||||
'geojson',
|
||||
'geojson_pubblicato',
|
||||
'impronta_pubblicata',
|
||||
'pdf_pubblicato',
|
||||
'pubblicata_at',
|
||||
'image_path',
|
||||
'rendered_at',
|
||||
@@ -110,9 +111,11 @@ class TerritorioMappa extends Model
|
||||
{
|
||||
$territorio = $this->territorio;
|
||||
|
||||
// Il territorio entra con il numero, non con l'id: il numero è unico e
|
||||
// il ripristino di un backup ricrea i territori con id nuovi, che
|
||||
// facevano risultare da pubblicare ogni piantina appena ripristinata.
|
||||
return hash('sha256', json_encode([
|
||||
$this->geometria(),
|
||||
$this->territorio_id,
|
||||
$territorio ? trim((string) $territorio->numero) : null,
|
||||
$territorio?->zona?->nome,
|
||||
$territorio ? trim((string) $territorio->confini) : null,
|
||||
@@ -131,15 +134,19 @@ class TerritorioMappa extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Il PDF in vigore del territorio è uno composto da una piantina. Se nel
|
||||
* frattempo è stato sostituito per altre vie (ripristino di una versione,
|
||||
* caricamento a mano, import), quello che arriva ai proclamatori non è
|
||||
* più questo disegno, anche se l'impronta torna.
|
||||
* Il PDF in vigore del territorio è ancora quello prodotto dall'ultima
|
||||
* pubblicazione. Se nel frattempo è stato sostituito per altre vie
|
||||
* (ripristino di una versione, caricamento a mano, import), quello che
|
||||
* arriva ai proclamatori non è più questo disegno, anche se l'impronta
|
||||
* torna. Si confronta il percorso, che il backup conserva: prima si
|
||||
* cercava l'id del territorio nel nome del file, e dopo un ripristino
|
||||
* (id nuovi) non tornava più.
|
||||
*/
|
||||
public function pdfInUsoDallaPiantina(): bool
|
||||
{
|
||||
return $this->territorio_id !== null
|
||||
&& str_starts_with((string) $this->territorio?->pdf_path, 'territori-pdf/piantina-' . $this->territorio_id . '-');
|
||||
return $this->pdf_pubblicato !== null
|
||||
&& $this->territorio !== null
|
||||
&& $this->territorio->pdf_path === $this->pdf_pubblicato;
|
||||
}
|
||||
|
||||
/** Il testo dell'etichetta di stato, uguale in ogni pagina. */
|
||||
|
||||
@@ -112,10 +112,12 @@ class BackupOperationState
|
||||
$stato = $this->get($id);
|
||||
|
||||
// Puntatore orfano (stato scaduto) o operazione gia' chiusa: il posto
|
||||
// e' libero, e il puntatore va tolto di mezzo.
|
||||
// e' libero. Il puntatore pero' qui non si tocca: corrente() la
|
||||
// chiamano anche le pagine che si aggiornano, fuori dal mutex di
|
||||
// occupa(), e cancellarlo poteva togliere quello che un'altra
|
||||
// richiesta aveva appena scritto per un'operazione nuova. Lo
|
||||
// sovrascrive initialize() al prossimo avvio.
|
||||
if ($stato === null || in_array($stato['status'] ?? '', ['completed', 'failed'], true)) {
|
||||
Cache::forget(self::CHIAVE_CORRENTE);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -296,8 +298,17 @@ class BackupOperationState
|
||||
*/
|
||||
private function liberaCorrente(string $id): void
|
||||
{
|
||||
if (Cache::get(self::CHIAVE_CORRENTE) === $id) {
|
||||
Cache::forget(self::CHIAVE_CORRENTE);
|
||||
// Leggi-e-cancella sotto lo stesso mutex di occupa(): fra i due passi
|
||||
// un'altra richiesta poteva prendere il posto, e il forget le toglieva
|
||||
// il puntatore. Se il mutex non arriva si lascia stare: il puntatore a
|
||||
// un'operazione chiusa vale già come posto libero (vedi corrente()).
|
||||
try {
|
||||
Cache::lock(self::CHIAVE_AVVIO, 10)->block(5, function () use ($id) {
|
||||
if (Cache::get(self::CHIAVE_CORRENTE) === $id) {
|
||||
Cache::forget(self::CHIAVE_CORRENTE);
|
||||
}
|
||||
});
|
||||
} catch (LockTimeoutException) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,9 @@ class PubblicazionePiantina
|
||||
$mappa->update([
|
||||
'geojson_pubblicato' => $mappa->geojson,
|
||||
'impronta_pubblicata' => $stato['impronta'],
|
||||
// Il PDF appena messo in vigore: finché il territorio usa questo
|
||||
// file, la piantina è "Pubblicata" (vedi pdfInUsoDallaPiantina()).
|
||||
'pdf_pubblicato' => $mappa->territorio->fresh()->pdf_path,
|
||||
'pubblicata_at' => now(),
|
||||
]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user