Sistema i buchi del badge Pagellone: soglia minima voti e voto limitato ai convocati
Il badge Pagellone si sblocca ora solo con almeno 5 pagelle ricevute (VOTI_MINIMI_PAGELLA): un voto solo poteva sbloccarlo o farlo sparire senza significatività statistica. Aggiunto Giocatore.votiPagella per farlo funzionare. La migration m13 (DD-027) estende le policy RLS di M11 su pagelle_voti, mvp_voti e badge_social_voti: votante e votato devono essere convocati all'evento (prima solo un filtro applicativo), e per le pagelle anche pagelle_chiuse=false. Le policy admin restano permissive di proposito. Applicata anche al progetto cloud. Copertura test completa: unit sulla soglia minima, integration sulle nuove policy RLS (permessi.test.ts) e un end-to-end reale (pagella-badge.test.ts) sul modello di mvp-badge.test.ts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
-- M13 — Le tabelle di voto controllano anche a database chi può votare chi.
|
||||
--
|
||||
-- Due gap segnalati in `docs/modules/badge.md` (audit del modulo Badge), entrambi finora
|
||||
-- solo filtri applicativi, aggirabili da chi scrive direttamente su PostgREST:
|
||||
--
|
||||
-- 1. Niente impediva di votare (o essere votati) da/per un giocatore non convocato
|
||||
-- all'evento — vale per pagelle_voti, mvp_voti, badge_social_voti.
|
||||
-- 2. `eventi_app.pagelle_chiuse` nascondeva solo i bottoni in UI: un voto "fuori tempo"
|
||||
-- restava tecnicamente possibile.
|
||||
--
|
||||
-- Le policy "Ognuno gestisce i propri voti ..." di M11 vengono estese con un controllo sui
|
||||
-- convocati dell'evento: `convocati` vuoto significa "tutta la rosa" (stessa convenzione di
|
||||
-- `convocatiEvento()` in eventi.ts), quindi il controllo si applica solo se la lista non è
|
||||
-- vuota. Le policy admin restano invariate: un amministratore può correggere un voto anche
|
||||
-- per un giocatore che non risultava convocato o dopo la chiusura delle pagelle.
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.evento_permette_voto(
|
||||
p_match_id text, p_votante_id text, p_votato_id text, p_richiede_pagelle_aperte boolean
|
||||
) RETURNS boolean
|
||||
LANGUAGE sql STABLE AS $$
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM public.eventi_app e
|
||||
WHERE e.id = p_match_id
|
||||
AND (cardinality(e.convocati) = 0 OR p_votante_id = ANY(e.convocati))
|
||||
AND (cardinality(e.convocati) = 0 OR p_votato_id = ANY(e.convocati))
|
||||
AND (NOT p_richiede_pagelle_aperte OR NOT e.pagelle_chiuse)
|
||||
);
|
||||
$$;
|
||||
|
||||
-- --- pagelle: anche convocazione e chiusura --------------------------------------------
|
||||
DROP POLICY "Ognuno gestisce i propri voti pagella" ON public.pagelle_voti;
|
||||
|
||||
CREATE POLICY "Ognuno gestisce i propri voti pagella" ON public.pagelle_voti
|
||||
FOR ALL TO authenticated
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.giocatori_squadra g
|
||||
WHERE g.id = votante_id AND g.auth_user_id = auth.uid()
|
||||
)
|
||||
AND public.evento_permette_voto(match_id, votante_id, votato_id, true)
|
||||
)
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.giocatori_squadra g
|
||||
WHERE g.id = votante_id AND g.auth_user_id = auth.uid()
|
||||
)
|
||||
AND public.evento_permette_voto(match_id, votante_id, votato_id, true)
|
||||
);
|
||||
|
||||
-- --- MVP: solo convocazione, la votazione non ha un flag di chiusura -------------------
|
||||
DROP POLICY "Ognuno gestisce il proprio voto MVP" ON public.mvp_voti;
|
||||
|
||||
CREATE POLICY "Ognuno gestisce il proprio voto MVP" ON public.mvp_voti
|
||||
FOR ALL TO authenticated
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.giocatori_squadra g
|
||||
WHERE g.id = votante_id AND g.auth_user_id = auth.uid()
|
||||
)
|
||||
AND public.evento_permette_voto(match_id, votante_id, votato_id, false)
|
||||
)
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.giocatori_squadra g
|
||||
WHERE g.id = votante_id AND g.auth_user_id = auth.uid()
|
||||
)
|
||||
AND public.evento_permette_voto(match_id, votante_id, votato_id, false)
|
||||
);
|
||||
|
||||
-- --- badge social: solo convocazione, stesso motivo -------------------------------------
|
||||
DROP POLICY "Ognuno gestisce i propri voti social" ON public.badge_social_voti;
|
||||
|
||||
CREATE POLICY "Ognuno gestisce i propri voti social" ON public.badge_social_voti
|
||||
FOR ALL TO authenticated
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.giocatori_squadra g
|
||||
WHERE g.id = votante_id AND g.auth_user_id = auth.uid()
|
||||
)
|
||||
AND public.evento_permette_voto(match_id, votante_id, votato_id, false)
|
||||
)
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.giocatori_squadra g
|
||||
WHERE g.id = votante_id AND g.auth_user_id = auth.uid()
|
||||
)
|
||||
AND public.evento_permette_voto(match_id, votante_id, votato_id, false)
|
||||
);
|
||||
Reference in New Issue
Block a user