-- Partien, Mitspieler, Wertung, Statistik, Profil-Sicht und Konto löschen. begin; select plan(39); insert into auth.users (id, email, raw_user_meta_data) values ('11111111-1111-1111-1111-111111111111', 'anna@example.com', '{"age_confirmed":"true","terms_accepted":"true","display_name":"Anna"}'), ('22222222-2222-2222-2222-222222222222', 'ben@example.com', '{"age_confirmed":"true","terms_accepted":"true","display_name":"Ben"}'), ('33333333-3333-3333-3333-333333333333', 'cara@example.com', '{"age_confirmed":"true","terms_accepted":"true","display_name":"Cara"}'), ('44444444-4444-4444-4444-444444444444', 'dan@example.com', '{"age_confirmed":"true","terms_accepted":"true","display_name":"Dan"}'); update public.profiles set city = 'Hannover' where id = '11111111-1111-1111-1111-111111111111'; update public.profiles set city = 'Bielefeld', city_visible = false where id = '22222222-2222-2222-2222-222222222222'; insert into public.games (id, title, visibility) values ('a0000000-0000-0000-0000-000000000001', 'Catan', 'catalog'); insert into public.games (id, title, visibility, owner_id) values ('a0000000-0000-0000-0000-000000000002', 'Annas Prototyp', 'private', '11111111-1111-1111-1111-111111111111'); insert into public.score_sheets (id, owner_id, name) values ('d0000000-0000-0000-0000-000000000001', '11111111-1111-1111-1111-111111111111', 'Catan Standard'), ('d0000000-0000-0000-0000-000000000002', '33333333-3333-3333-3333-333333333333', 'Caras Bogen'); insert into public.score_categories (id, sheet_id, name, position) values ('e0000000-0000-0000-0000-000000000001', 'd0000000-0000-0000-0000-000000000001', 'Siedlungen', 0), ('e0000000-0000-0000-0000-000000000002', 'd0000000-0000-0000-0000-000000000001', 'Straßen', 1); -- ===== Anna legt Partien an ===== select set_config('request.jwt.claims', '{"sub":"11111111-1111-1111-1111-111111111111","role":"authenticated"}', true); set local role authenticated; select lives_ok( $$insert into public.plays (id, owner_id, game_id, sheet_id, played_at, duration_minutes, client_id) values ('f0000000-0000-0000-0000-000000000001', '11111111-1111-1111-1111-111111111111', 'a0000000-0000-0000-0000-000000000001', 'd0000000-0000-0000-0000-000000000001', '2026-10-01 19:00+00', 90, '90000000-0000-0000-0000-000000000001')$$, 'Anna darf eine Partie anlegen'); select throws_ok( $$insert into public.plays (owner_id, game_id, played_at, client_id) values ('11111111-1111-1111-1111-111111111111', 'a0000000-0000-0000-0000-000000000001', '2026-10-01 19:00+00', '90000000-0000-0000-0000-000000000001')$$, '23505', null, 'Dieselbe client_id wird nicht doppelt angelegt (Offline-Abgleich)'); select throws_ok( $$insert into public.plays (owner_id, game_id, played_at, client_id) values ('22222222-2222-2222-2222-222222222222', 'a0000000-0000-0000-0000-000000000001', '2026-10-01 19:00+00', '90000000-0000-0000-0000-000000000009')$$, '42501', null, 'Anna kann keine Partien für andere anlegen'); select throws_ok( $$insert into public.plays (owner_id, game_id, sheet_id, played_at, client_id) values ('11111111-1111-1111-1111-111111111111', 'a0000000-0000-0000-0000-000000000001', 'd0000000-0000-0000-0000-000000000002', '2026-10-01 19:00+00', '90000000-0000-0000-0000-000000000008')$$, '42501', null, 'Anna kann keinen fremden Wertungsbogen verwenden'); select throws_ok( $$insert into public.plays (owner_id, game_id, played_at, note, client_id) values ('11111111-1111-1111-1111-111111111111', 'a0000000-0000-0000-0000-000000000001', '2026-10-01 19:00+00', repeat('x', 1001), '90000000-0000-0000-0000-000000000007')$$, '23514', null, 'Notiz ist auf 1000 Zeichen begrenzt'); -- Mitspieler: sie selbst, ein Gast, Ben (Einladung), Cara (Einladung) select lives_ok( $$insert into public.play_players (id, play_id, profile_id, link_status, place, total_score) values ('f1000000-0000-0000-0000-000000000001', 'f0000000-0000-0000-0000-000000000001', '11111111-1111-1111-1111-111111111111', 'confirmed', 1, 10)$$, 'Anna trägt sich selbst als Mitspielerin ein'); select lives_ok( $$insert into public.play_players (play_id, guest_name, link_status, place, total_score) values ('f0000000-0000-0000-0000-000000000001', 'Opa', 'none', 2, 8)$$, 'Anna darf einen Gast eintragen'); select lives_ok( $$insert into public.play_players (id, play_id, profile_id, link_status, place, total_score) values ('f1000000-0000-0000-0000-000000000003', 'f0000000-0000-0000-0000-000000000001', '22222222-2222-2222-2222-222222222222', 'pending', 3, 6)$$, 'Anna darf Ben einladen (offen)'); select throws_ok( $$insert into public.play_players (play_id, profile_id, link_status) values ('f0000000-0000-0000-0000-000000000001', '33333333-3333-3333-3333-333333333333', 'confirmed')$$, '42501', null, 'Anna kann Cara nicht selbst als bestätigt eintragen'); select throws_ok( $$insert into public.play_players (play_id, guest_name, link_status) values ('f0000000-0000-0000-0000-000000000001', 'Bella', 'confirmed')$$, '42501', null, 'Ein Gast kann nicht als bestätigt eingetragen werden'); select throws_ok( $$update public.play_players set link_status = 'confirmed' where id = 'f1000000-0000-0000-0000-000000000003'$$, 'P0001', 'link_change_not_allowed', 'Anna kann Bens Einladung nicht selbst bestätigen'); select lives_ok( $$update public.play_players set place = 2, total_score = 9 where id = 'f1000000-0000-0000-0000-000000000003'$$, 'Anna darf Platz und Punkte ändern'); -- Wertungsbogen und Werte select lives_ok( $$insert into public.play_scores (play_player_id, category_id, value) values ('f1000000-0000-0000-0000-000000000001', 'e0000000-0000-0000-0000-000000000001', 6), ('f1000000-0000-0000-0000-000000000001', 'e0000000-0000-0000-0000-000000000002', 4)$$, 'Anna darf Einzelwerte erfassen'); select throws_ok( $$insert into public.play_scores (play_player_id, category_id, value) values ('f1000000-0000-0000-0000-000000000001', 'e0000000-0000-0000-0000-000000000001', 7)$$, '23505', null, 'Je Mitspieler und Kategorie gibt es einen Wert'); -- Limit von 20 Mitspielern (3 vorhanden, 17 weitere sind erlaubt) select lives_ok( $$insert into public.play_players (play_id, guest_name) select 'f0000000-0000-0000-0000-000000000001', 'Gast ' || g from generate_series(1, 17) g$$, 'Bis 20 Mitspieler sind erlaubt'); select throws_ok( $$insert into public.play_players (play_id, guest_name) values ('f0000000-0000-0000-0000-000000000001', 'Zu viel')$$, 'P0001', 'play_players_limit_exceeded', 'Der 21. Mitspieler wird abgelehnt'); reset role; -- ===== Ben (eingeladen, noch offen) ===== select set_config('request.jwt.claims', '{"sub":"22222222-2222-2222-2222-222222222222","role":"authenticated"}', true); set local role authenticated; select is((select count(*) from public.plays), 1::bigint, 'Ben sieht die Partie, zu der er eingeladen ist'); select is((select count(*) from public.my_game_stats), 0::bigint, 'Offene Einladungen zählen nicht in die Statistik'); select is((select count(*) from public.public_profiles), 2::bigint, 'Ben sieht sich und die Einladende'); select is((select city from public.public_profiles where id = '11111111-1111-1111-1111-111111111111'), 'Hannover', 'Stadt ist sichtbar, wenn freigegeben'); select throws_ok( $$update public.play_players set place = 1 where id = 'f1000000-0000-0000-0000-000000000003'$$, 'P0001', 'invitation_answer_only', 'Ben darf nur die Einladung beantworten, nichts sonst ändern'); select is_empty($$update public.play_players set link_status = 'confirmed' where id = 'f1000000-0000-0000-0000-000000000001' returning 1$$, 'Ben kann nicht für andere bestätigen'); select throws_ok( $$insert into public.play_scores (play_player_id, category_id, value) values ('f1000000-0000-0000-0000-000000000003', 'e0000000-0000-0000-0000-000000000001', 5)$$, '42501', null, 'Ben kann keine Werte erfassen'); select is_empty($$update public.plays set note = 'Fremd' returning 1$$, 'Ben kann die Partie nicht ändern'); select lives_ok( $$update public.play_players set link_status = 'confirmed' where id = 'f1000000-0000-0000-0000-000000000003'$$, 'Ben darf seine Einladung bestätigen'); select is((select count(*) from public.play_scores), 2::bigint, 'Bestätigte Mitspieler sehen die Werte'); select is((select count(*) from public.score_sheets), 0::bigint, 'Ben sieht Annas Wertungsbogen nicht'); select is((select play_count from public.my_game_stats), 1::bigint, 'Bestätigte Partien zählen in die Statistik'); reset role; -- ===== Cara (eingeladen, lehnt ab) und Dan (Fremder) ===== -- Aufbau als Superuser: keine Nutzer-Claims aktiv select set_config('request.jwt.claims', '', true); update public.play_players set profile_id = '33333333-3333-3333-3333-333333333333', guest_name = null, link_status = 'pending' where play_id = 'f0000000-0000-0000-0000-000000000001' and guest_name = 'Gast 1'; select set_config('request.jwt.claims', '{"sub":"33333333-3333-3333-3333-333333333333","role":"authenticated"}', true); set local role authenticated; select lives_ok( $$update public.play_players set link_status = 'declined' where profile_id = '33333333-3333-3333-3333-333333333333'$$, 'Cara darf die Einladung ablehnen'); select is((select count(*) from public.plays), 0::bigint, 'Wer abgelehnt hat, sieht die Partie nicht mehr'); select is((select count(*) from public.play_players), 1::bigint, 'Cara sieht nur ihre eigene Zeile'); reset role; select set_config('request.jwt.claims', '{"sub":"44444444-4444-4444-4444-444444444444","role":"authenticated"}', true); set local role authenticated; select is((select count(*) from public.plays), 0::bigint, 'Fremde sehen keine Partien'); select is((select count(*) from public.play_players), 0::bigint, 'Fremde sehen keine Mitspieler'); select is((select count(*) from public.play_scores), 0::bigint, 'Fremde sehen keine Werte'); select is((select count(*) from public.public_profiles), 1::bigint, 'Fremde sehen nur sich selbst, es gibt keine Nutzersuche'); reset role; -- ===== Statistik: Siegquote zählt nur Partien mit Ergebnis ===== select set_config('request.jwt.claims', '', true); insert into public.plays (id, owner_id, game_id, played_at, duration_minutes, client_id) values ('f0000000-0000-0000-0000-000000000002', '11111111-1111-1111-1111-111111111111', 'a0000000-0000-0000-0000-000000000001', '2026-10-02', 60, '90000000-0000-0000-0000-000000000002'), ('f0000000-0000-0000-0000-000000000003', '11111111-1111-1111-1111-111111111111', 'a0000000-0000-0000-0000-000000000001', '2026-10-03', 30, '90000000-0000-0000-0000-000000000003'); insert into public.play_players (play_id, profile_id, link_status, place) values ('f0000000-0000-0000-0000-000000000002', '11111111-1111-1111-1111-111111111111', 'confirmed', 2), ('f0000000-0000-0000-0000-000000000003', '11111111-1111-1111-1111-111111111111', 'confirmed', null); select set_config('request.jwt.claims', '{"sub":"11111111-1111-1111-1111-111111111111","role":"authenticated"}', true); set local role authenticated; select results_eq( $$select play_count, total_minutes, wins, plays_with_result, win_rate from public.my_game_stats where game_id = 'a0000000-0000-0000-0000-000000000001'$$, $$values (3::bigint, 180::bigint, 1::bigint, 2::bigint, 0.5000::numeric)$$, 'Statistik: 3 Partien, 180 Minuten, 1 Sieg bei 2 Partien mit Ergebnis, Siegquote 0,5'); reset role; -- ===== Konto löschen: Partien bleiben für andere, ohne Beteiligte verschwinden sie ===== select set_config('request.jwt.claims', '', true); delete from auth.users where id = '11111111-1111-1111-1111-111111111111'; select is((select count(*) from public.plays), 1::bigint, 'Nach dem Löschen bleibt nur die Partie mit einem anderen bestätigten Mitspieler'); select is((select owner_id is null from public.plays), true, 'Die Partie hat keinen Ersteller mehr'); select is((select count(*) from public.play_players where profile_id is null and guest_name is null and link_status = 'none'), 1::bigint, 'Der gelöschte Nutzer erscheint anonym'); select * from finish(); rollback;