forked from wrenn/wrenn
Fix cascading deletion gaps for user and team cleanup
- Add ON DELETE CASCADE to users_teams, oauth_providers, admin_permissions and ON DELETE SET NULL (with nullable columns) to team_api_keys.created_by, hosts.created_by, host_tokens.created_by so HardDeleteExpiredUsers no longer fails with FK violations - User account deletion now cascades to sole-owned teams via DeleteTeamInternal, preventing orphaned teams with live sandboxes after account removal - ListActiveSandboxesByTeam now includes hibernated sandboxes so their disk snapshots are cleaned up during team deletion - Team soft-delete now hard-deletes sandbox metric points, metric snapshots, API keys, and channels to prevent data accumulation on deleted teams - Extract deleteTeamCore() to deduplicate shared logic across DeleteTeam, AdminDeleteTeam, and DeleteTeamInternal - Fix ListAPIKeysByTeamWithCreator to use LEFT JOIN after created_by became nullable, and update handler to read pgtype.Text.String for creator_email
This commit is contained in:
@ -13,7 +13,7 @@ SELECT * FROM team_api_keys WHERE team_id = $1 ORDER BY created_at DESC;
|
||||
SELECT k.id, k.team_id, k.name, k.key_hash, k.key_prefix, k.created_by, k.created_at, k.last_used,
|
||||
u.email AS creator_email
|
||||
FROM team_api_keys k
|
||||
JOIN users u ON u.id = k.created_by
|
||||
LEFT JOIN users u ON u.id = k.created_by
|
||||
WHERE k.team_id = $1
|
||||
ORDER BY k.created_at DESC;
|
||||
|
||||
@ -22,3 +22,6 @@ DELETE FROM team_api_keys WHERE id = $1 AND team_id = $2;
|
||||
|
||||
-- name: UpdateAPIKeyLastUsed :exec
|
||||
UPDATE team_api_keys SET last_used = NOW() WHERE id = $1;
|
||||
|
||||
-- name: DeleteAPIKeysByTeam :exec
|
||||
DELETE FROM team_api_keys WHERE team_id = $1;
|
||||
|
||||
@ -22,6 +22,9 @@ RETURNING *;
|
||||
-- name: DeleteChannelByTeam :exec
|
||||
DELETE FROM channels WHERE id = $1 AND team_id = $2;
|
||||
|
||||
-- name: DeleteAllChannelsByTeam :exec
|
||||
DELETE FROM channels WHERE team_id = $1;
|
||||
|
||||
-- name: ListChannelsForEvent :many
|
||||
SELECT * FROM channels
|
||||
WHERE team_id = $1
|
||||
|
||||
@ -51,6 +51,13 @@ WHERE sandbox_id = $1 AND tier = $2;
|
||||
DELETE FROM sandbox_metric_points
|
||||
WHERE ts < EXTRACT(EPOCH FROM NOW() - INTERVAL '30 days')::BIGINT;
|
||||
|
||||
-- name: DeleteMetricsSnapshotsByTeam :exec
|
||||
DELETE FROM sandbox_metrics_snapshots WHERE team_id = $1;
|
||||
|
||||
-- name: DeleteMetricPointsByTeam :exec
|
||||
DELETE FROM sandbox_metric_points
|
||||
WHERE sandbox_id IN (SELECT id FROM sandboxes WHERE team_id = $1);
|
||||
|
||||
-- name: SampleSandboxMetrics :many
|
||||
-- Aggregates per-team resource usage from the live sandboxes table.
|
||||
-- Groups by all teams that have any sandbox row (including stopped) so that
|
||||
|
||||
@ -62,7 +62,7 @@ WHERE id = ANY($1::uuid[]);
|
||||
|
||||
-- name: ListActiveSandboxesByTeam :many
|
||||
SELECT * FROM sandboxes
|
||||
WHERE team_id = $1 AND status IN ('running', 'paused', 'starting')
|
||||
WHERE team_id = $1 AND status IN ('running', 'paused', 'starting', 'hibernated')
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: MarkSandboxesMissingByHost :exec
|
||||
|
||||
@ -74,6 +74,18 @@ WHERE t.id != '00000000-0000-0000-0000-000000000000'
|
||||
ORDER BY t.deleted_at ASC NULLS FIRST, t.created_at DESC
|
||||
LIMIT $1 OFFSET $2;
|
||||
|
||||
-- name: ListSoleOwnedTeams :many
|
||||
-- Returns teams where the user is the owner and no other members exist.
|
||||
SELECT t.id FROM teams t
|
||||
JOIN users_teams ut ON ut.team_id = t.id
|
||||
WHERE ut.user_id = $1
|
||||
AND ut.role = 'owner'
|
||||
AND t.deleted_at IS NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM users_teams ut2
|
||||
WHERE ut2.team_id = t.id AND ut2.user_id <> $1
|
||||
);
|
||||
|
||||
-- name: CountTeamsAdmin :one
|
||||
SELECT COUNT(*)::int AS total
|
||||
FROM teams
|
||||
|
||||
Reference in New Issue
Block a user