fix(data): enforce completed portfolio sessions

This commit is contained in:
2026-06-01 15:04:20 +03:00
parent f493836b77
commit da0a306340
7 changed files with 336 additions and 75 deletions
+5 -3
View File
@@ -4,16 +4,18 @@ var postgres = builder.AddPostgres("postgres")
.WithPgAdmin()
.AddDatabase("gmrelay-db");
builder.AddProject<Projects.GmRelay_Bot>("bot")
var bot = builder.AddProject<Projects.GmRelay_Bot>("bot")
.WithReference(postgres)
.WaitFor(postgres);
builder.AddProject<Projects.GmRelay_DiscordBot>("discord")
.WithReference(postgres)
.WaitFor(postgres);
.WaitFor(postgres)
.WaitFor(bot);
builder.AddProject<Projects.GmRelay_Web>("web")
.WithReference(postgres)
.WaitFor(postgres);
.WaitFor(postgres)
.WaitFor(bot);
builder.Build().Run();
@@ -58,13 +58,18 @@ LANGUAGE plpgsql
AS $$
DECLARE
target_portfolio_game_id UUID;
target_portfolio_game_ids UUID[];
BEGIN
PERFORM pg_advisory_xact_lock(20260530, 108);
IF TG_TABLE_NAME = 'portfolio_games' THEN
target_portfolio_game_id := NEW.id;
target_portfolio_game_ids := ARRAY[NEW.id];
ELSIF TG_OP = 'DELETE' THEN
target_portfolio_game_ids := ARRAY[OLD.portfolio_game_id];
ELSIF TG_OP = 'INSERT' THEN
target_portfolio_game_ids := ARRAY[NEW.portfolio_game_id];
ELSE
target_portfolio_game_id := OLD.portfolio_game_id;
target_portfolio_game_ids := ARRAY[OLD.portfolio_game_id, NEW.portfolio_game_id];
END IF;
IF current_setting('transaction_isolation') <> 'read committed' THEN
@@ -73,24 +78,33 @@ BEGIN
USING ERRCODE = '0A000';
END IF;
IF EXISTS (
SELECT 1
FROM portfolio_games pg
WHERE pg.id = target_portfolio_game_id
AND pg.is_public = true
AND (
NOT EXISTS (
SELECT 1
FROM portfolio_game_sessions pgs
WHERE pgs.portfolio_game_id = target_portfolio_game_id
)
OR NOT EXISTS (
SELECT 1
FROM portfolio_game_masters pgm
WHERE pgm.portfolio_game_id = target_portfolio_game_id
)
SELECT pg.id
INTO target_portfolio_game_id
FROM portfolio_games pg
WHERE pg.id = ANY(target_portfolio_game_ids)
AND pg.is_public = true
AND (
NOT EXISTS (
SELECT 1
FROM portfolio_game_sessions pgs
WHERE pgs.portfolio_game_id = pg.id
)
) THEN
OR EXISTS (
SELECT 1
FROM portfolio_game_sessions pgs
JOIN sessions s ON s.id = pgs.session_id
WHERE pgs.portfolio_game_id = pg.id
AND s.scheduled_at >= now()
)
OR NOT EXISTS (
SELECT 1
FROM portfolio_game_masters pgm
WHERE pgm.portfolio_game_id = pg.id
)
)
LIMIT 1;
IF target_portfolio_game_id IS NOT NULL THEN
RAISE EXCEPTION
'published portfolio game % must have at least one linked session and at least one linked master',
target_portfolio_game_id
@@ -101,6 +115,32 @@ BEGIN
END;
$$;
CREATE FUNCTION unpublish_public_portfolio_games_for_future_session()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
IF OLD.scheduled_at IS DISTINCT FROM NEW.scheduled_at
AND NEW.scheduled_at >= now() THEN
UPDATE portfolio_games pg
SET is_public = false,
updated_at = now()
FROM portfolio_game_sessions pgs
WHERE pgs.portfolio_game_id = pg.id
AND pgs.session_id = NEW.id
AND pg.is_public = true;
END IF;
RETURN NULL;
END;
$$;
CREATE CONSTRAINT TRIGGER trg_sessions_unpublish_public_portfolio_games_for_future_reschedule
AFTER UPDATE OF scheduled_at ON sessions
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE FUNCTION unpublish_public_portfolio_games_for_future_session();
CREATE CONSTRAINT TRIGGER trg_portfolio_games_validate_required_links
AFTER INSERT OR UPDATE OF is_public ON portfolio_games
DEFERRABLE INITIALLY DEFERRED
@@ -108,7 +148,7 @@ FOR EACH ROW
EXECUTE FUNCTION validate_public_portfolio_game_required_links();
CREATE CONSTRAINT TRIGGER trg_portfolio_game_sessions_validate_required_links
AFTER DELETE OR UPDATE OF portfolio_game_id ON portfolio_game_sessions
AFTER INSERT OR DELETE OR UPDATE OF portfolio_game_id, session_id ON portfolio_game_sessions
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE FUNCTION validate_public_portfolio_game_required_links();