Sposta avatar e documenti profilo su PocketBase (file field)
Sostituisce i due bucket Supabase Storage con campi file PocketBase:
- avatar-giocatori: nuova collection avatar_giocatori separata da
giocatori_squadra, perché la policy originale ("chiunque autenticato
carica/sostituisce/elimina qualsiasi avatar, nessun controllo
proprietario") è più permissiva delle regole di giocatori_squadra —
mescolarle avrebbe indebolito le une o bloccato l'altra. File pubblico,
come il bucket originale;
- profili-giocatore: campi file su profili_giocatore stesso, con
protected: true (vedi sotto).
Trovato e corretto un problema di sicurezza reale: PocketBase rende i
file pubblici di default (si affida solo alla casualità del nome file),
a meno di impostare esplicitamente protected: true sul campo — i
documenti d'identità e i certificati medici sarebbero stati raggiungibili
senza autenticazione, in violazione di DD-016 regola 4. Verificato che
ora servono un token valido (404 senza, 200 con).
La scrittura dei campi testuali del profilo e il caricamento dei file
sono due operazioni separate (PocketBase rifiuta una stringa dove si
aspetta un file): verificato che caricare un documento non cancella i
dati testuali già salvati.
Rimossi da profili-core.ts RigaProfilo/daRigaProfilo/aRigaProfilo
(shape Postgres non più usata da nessun modulo di produzione) e
rimuoviFile (mai chiamato da nessun componente). Avatar.tsx non usa più
un URL deterministico per giocatore: PocketBase genera nomi file
casuali, quindi legge la mappa avatar tramite una query React Query
condivisa tra tutte le istanze del componente.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
/** Check dei profili giocatore: `bun test/unit/profili-core.test.ts`. */
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
aRigaProfilo,
|
||||
completamento,
|
||||
csvTesseramento,
|
||||
daRigaProfilo,
|
||||
sezioniComplete,
|
||||
statoScadenza,
|
||||
type Profilo,
|
||||
@@ -19,6 +17,7 @@ import {
|
||||
import { dividiNome } from "@/lib/crapp-data";
|
||||
|
||||
const vuoto: Profilo = {
|
||||
id: null,
|
||||
giocatoreId: "g1",
|
||||
dataNascita: null,
|
||||
luogoNascita: null,
|
||||
@@ -77,17 +76,6 @@ assert.equal(
|
||||
);
|
||||
assert.equal(sezioniComplete({ ...completo, documentoFrontePath: null }).documento, false);
|
||||
|
||||
// --- aRigaProfilo ------------------------------------------------------------
|
||||
const riga = aRigaProfilo({ ...completo, luogoNascita: " ", telefono: " 333 " });
|
||||
assert.equal(riga.luogo_nascita, null, "i campi solo-spazi tornano NULL, non stringa vuota");
|
||||
assert.equal(riga.telefono, "333", "il resto viene ripulito ai bordi");
|
||||
assert.equal(riga.documento_fronte_path, "g1/documento-fronte.jpg");
|
||||
assert.deepEqual(
|
||||
daRigaProfilo(aRigaProfilo(completo)),
|
||||
completo,
|
||||
"modello -> riga -> modello non perde niente",
|
||||
);
|
||||
|
||||
// --- statoScadenza -----------------------------------------------------------
|
||||
const oggi = "2026-08-30";
|
||||
assert.equal(statoScadenza(null, null, oggi), "mancante");
|
||||
|
||||
Reference in New Issue
Block a user