117 lines
5.7 KiB
MySQL
117 lines
5.7 KiB
MySQL
|
|
-- =====================================================================
|
||
|
|
-- TeeCup — migrasjon 007
|
||
|
|
-- Selvregistrering + utvidet spillerprofil (ADR-017)
|
||
|
|
-- =====================================================================
|
||
|
|
-- Kjøres etter 001-006. Alt additivt (nullable eller default) bortsett fra
|
||
|
|
-- den nye tabellen, som er helt ny.
|
||
|
|
-- =====================================================================
|
||
|
|
|
||
|
|
\set ON_ERROR_STOP on
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
-- 1. Utvidet spillerprofil (ADR-017 Beslutning D)
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
ALTER TABLE player ADD COLUMN mobile text;
|
||
|
|
ALTER TABLE player ADD COLUMN email text;
|
||
|
|
ALTER TABLE player ADD COLUMN birth_date date;
|
||
|
|
ALTER TABLE player ADD COLUMN nickname text;
|
||
|
|
ALTER TABLE player ADD COLUMN country text;
|
||
|
|
ALTER TABLE player ADD COLUMN club text;
|
||
|
|
ALTER TABLE player ADD COLUMN club_member_number text;
|
||
|
|
|
||
|
|
-- Bevisst IKKE en UNIQUE-constraint på e-post: familier deler av og til
|
||
|
|
-- e-post (forelder melder på barn), og en hard unik-regel ville krasje
|
||
|
|
-- akkurat den vanlige situasjonen. E-postmatching ved påmelding/innlogging
|
||
|
|
-- (ADR-017 Beslutning B) er derfor et mykt, applikasjonslags-oppslag, ikke
|
||
|
|
-- en databasegaranti.
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
-- 2. Påmeldingsinnstillinger på turnering (ADR-017 Beslutning C)
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
ALTER TABLE tournament ADD COLUMN registration_deadline timestamptz;
|
||
|
|
|
||
|
|
ALTER TABLE tournament ADD COLUMN registration_capacity integer
|
||
|
|
CHECK (registration_capacity IS NULL OR registration_capacity > 0);
|
||
|
|
|
||
|
|
ALTER TABLE tournament ADD COLUMN registration_overflow_policy text
|
||
|
|
NOT NULL DEFAULT 'closed'
|
||
|
|
CHECK (registration_overflow_policy IN ('waitlist', 'closed'));
|
||
|
|
|
||
|
|
ALTER TABLE tournament ADD COLUMN registration_requires_approval boolean
|
||
|
|
NOT NULL DEFAULT false;
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
-- 3. tournament_registration (ADR-017 Beslutning C)
|
||
|
|
--
|
||
|
|
-- Bevisst ATSKILT fra team_roster: en registrering betyr "vil kanskje
|
||
|
|
-- spille", team_roster betyr "committed til et bestemt lag". Organisator
|
||
|
|
-- forfremmer en registrering til roster via de eksisterende
|
||
|
|
-- team-/roster-endepunktene -- denne tabellen påvirker ALDRI team_roster
|
||
|
|
-- automatisk.
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
CREATE TABLE tournament_registration (
|
||
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
|
organization_id uuid NOT NULL,
|
||
|
|
tournament_id uuid NOT NULL,
|
||
|
|
player_id uuid NOT NULL,
|
||
|
|
status text NOT NULL DEFAULT 'pending'
|
||
|
|
CHECK (status IN ('pending', 'confirmed', 'waitlisted', 'declined', 'withdrawn')),
|
||
|
|
registered_at timestamptz NOT NULL DEFAULT now(),
|
||
|
|
-- Bevis for at samtykke faktisk ble gitt ved innsending, ikke bare
|
||
|
|
-- antatt (ADR-017). API-laget skal avvise innsending uten samtykke --
|
||
|
|
-- NOT NULL her er den siste linjen av forsvar, ikke den eneste.
|
||
|
|
consent_given_at timestamptz NOT NULL,
|
||
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
||
|
|
FOREIGN KEY (organization_id, tournament_id)
|
||
|
|
REFERENCES tournament(organization_id, id) ON DELETE CASCADE,
|
||
|
|
FOREIGN KEY (organization_id, player_id)
|
||
|
|
REFERENCES player(organization_id, id) ON DELETE RESTRICT,
|
||
|
|
UNIQUE (organization_id, id), -- for sammensatte FK-er
|
||
|
|
UNIQUE (tournament_id, player_id) -- én registrering per spiller per turnering
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE INDEX ON tournament_registration (organization_id, tournament_id);
|
||
|
|
|
||
|
|
-- RLS: samme org-isolasjon som resten (ADR-003). Skrevet direkte med
|
||
|
|
-- app_current_org() siden denne tabellen kommer etter 005-fiksen -- ingen
|
||
|
|
-- grunn til å reprodusere tomstreng-buggen bare for å rette den igjen.
|
||
|
|
ALTER TABLE tournament_registration ENABLE ROW LEVEL SECURITY;
|
||
|
|
ALTER TABLE tournament_registration FORCE ROW LEVEL SECURITY;
|
||
|
|
CREATE POLICY org_isolation ON tournament_registration
|
||
|
|
USING (organization_id = app_current_org())
|
||
|
|
WITH CHECK (organization_id = app_current_org());
|
||
|
|
|
||
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON tournament_registration TO teecup_app;
|
||
|
|
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
-- 4. public_tournament_org() -- den ENESTE broen fra en uautentisert
|
||
|
|
-- forespørsel (ingen app.current_org satt ennå) til riktig org-kontekst
|
||
|
|
-- (ADR-017 Beslutning A).
|
||
|
|
--
|
||
|
|
-- SECURITY DEFINER: kjører med skaperens rettigheter (teeoff_admin, som
|
||
|
|
-- har BYPASSRLS) slik at oppslaget kan lese `tournament` FØR RLS-
|
||
|
|
-- konteksten er kjent -- det er selve poenget, ikke et hull. Eksponerer
|
||
|
|
-- KUN organization_id for en gitt turnering-id, ingenting annet fra
|
||
|
|
-- tournament-raden. `SET search_path = public` hindrer search_path-
|
||
|
|
-- kapring (standard herding for SECURITY DEFINER-funksjoner).
|
||
|
|
--
|
||
|
|
-- Bruksmønster i app-laget: slå opp org_id via denne FØRST, åpne deretter
|
||
|
|
-- en vanlig org_connection(org_id) og fortsett med normal RLS-håndhevelse
|
||
|
|
-- for alt det faktiske arbeidet (sjekk frist/kapasitet, sett inn
|
||
|
|
-- registrering). Samme "løs kontekst-problemet FØR RLS kan håndheve
|
||
|
|
-- noe"-mønster som selvrefererende org-bootstrap (app/routers/
|
||
|
|
-- organizations.py), nå for et lese-oppslag i stedet for en innsetting.
|
||
|
|
-- ---------------------------------------------------------------------
|
||
|
|
CREATE FUNCTION public_tournament_org(p_tournament_id uuid)
|
||
|
|
RETURNS uuid
|
||
|
|
LANGUAGE sql
|
||
|
|
SECURITY DEFINER
|
||
|
|
SET search_path = public
|
||
|
|
STABLE
|
||
|
|
AS $$
|
||
|
|
SELECT organization_id FROM tournament WHERE id = p_tournament_id;
|
||
|
|
$$;
|
||
|
|
|
||
|
|
GRANT EXECUTE ON FUNCTION public_tournament_org(uuid) TO teecup_app;
|