Skip to content

Commit ee29cbf

Browse files
committed
fix(db): enforce workspace metadata contracts
1 parent 1c65305 commit ee29cbf

3 files changed

Lines changed: 296 additions & 96 deletions

File tree

‎supabase/migrations/20260920174841_debate_workspace_foundation.sql‎

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ CREATE FUNCTION public.update_workspace_document(
254254
p_side text,
255255
p_ordered_ids uuid[],
256256
p_assignee_id uuid,
257+
p_assignee_changed boolean,
257258
p_state text,
258259
p_expected_revision bigint,
259260
p_request_id uuid
@@ -287,6 +288,7 @@ BEGIN
287288
'side', p_side,
288289
'ordered_ids', to_jsonb(p_ordered_ids),
289290
'assignee', p_assignee_id,
291+
'assignee_changed', p_assignee_changed,
290292
'state', p_state,
291293
'expected_revision', p_expected_revision
292294
));
@@ -304,6 +306,8 @@ BEGIN
304306
END IF;
305307

306308
IF p_workspace_id IS NULL OR p_document_id IS NULL OR p_expected_revision < 0
309+
OR p_assignee_changed IS NULL
310+
OR (NOT p_assignee_changed AND p_assignee_id IS NOT NULL)
307311
OR (p_title IS NOT NULL AND (v_title = '' OR length(v_title) > 200))
308312
OR (p_side IS NOT NULL AND p_side NOT IN ('pro', 'con'))
309313
OR (p_state IS NOT NULL AND p_state NOT IN ('active', 'archived', 'trashed')) THEN
@@ -335,7 +339,7 @@ BEGIN
335339
IF NOT FOUND THEN
336340
RAISE EXCEPTION 'workspace unavailable';
337341
END IF;
338-
IF p_assignee_id IS NOT NULL AND NOT EXISTS (
342+
IF p_assignee_changed AND p_assignee_id IS NOT NULL AND NOT EXISTS (
339343
SELECT 1 FROM public.workspace_members
340344
WHERE workspace_id = p_workspace_id AND user_id = p_assignee_id
341345
) THEN
@@ -345,10 +349,23 @@ BEGIN
345349
v_side := coalesce(p_side, v_document.side);
346350
v_state := coalesce(p_state, v_document.state);
347351

352+
IF v_document.state = 'trashed' AND v_state <> 'trashed'
353+
AND v_document.trash_expires_at <= now() THEN
354+
RAISE EXCEPTION 'workspace unavailable';
355+
END IF;
356+
IF v_state = 'active'
357+
AND (v_document.state <> 'active' OR v_side <> v_document.side)
358+
AND p_ordered_ids IS NULL THEN
359+
RAISE EXCEPTION 'invalid document order';
360+
END IF;
361+
348362
UPDATE public.workspace_documents
349363
SET title = coalesce(v_title, v_document.title),
350364
side = v_side,
351-
assignee_id = p_assignee_id,
365+
assignee_id = CASE
366+
WHEN p_assignee_changed THEN p_assignee_id
367+
ELSE v_document.assignee_id
368+
END,
352369
state = v_state,
353370
trashed_at = CASE
354371
WHEN v_state = 'trashed' AND v_document.state <> 'trashed' THEN now()
@@ -403,7 +420,8 @@ BEGIN
403420
)
404421
VALUES (
405422
p_request_id, v_fingerprint, p_workspace_id, p_document_id, v_user_id,
406-
'document_update', v_workspace.revision, v_new_revision, p_assignee_id
423+
'document_update', v_workspace.revision, v_new_revision,
424+
CASE WHEN p_assignee_changed THEN p_assignee_id ELSE NULL END
407425
);
408426

409427
RETURN v_new_revision;
@@ -606,7 +624,10 @@ BEGIN
606624
)
607625
FOR UPDATE;
608626

609-
IF NOT FOUND OR v_workspace.owner_id <> v_user_id THEN
627+
IF NOT FOUND THEN
628+
RAISE EXCEPTION 'workspace unavailable';
629+
END IF;
630+
IF p_action IN ('delete', 'restore') AND v_workspace.owner_id <> v_user_id THEN
610631
RAISE EXCEPTION 'workspace unavailable';
611632
END IF;
612633
IF v_workspace.revision <> p_expected_revision THEN
@@ -651,14 +672,14 @@ $$;
651672

652673
REVOKE ALL ON FUNCTION public.create_workspace(text, text, text, uuid)
653674
FROM PUBLIC, anon;
654-
REVOKE ALL ON FUNCTION public.update_workspace_document(uuid, uuid, text, text, uuid[], uuid, text, bigint, uuid)
675+
REVOKE ALL ON FUNCTION public.update_workspace_document(uuid, uuid, text, text, uuid[], uuid, boolean, text, bigint, uuid)
655676
FROM PUBLIC, anon;
656677
REVOKE ALL ON FUNCTION public.change_workspace_access(uuid, text, uuid, bigint, uuid)
657678
FROM PUBLIC, anon;
658679
REVOKE ALL ON FUNCTION public.change_workspace_state(uuid, text, bigint, uuid)
659680
FROM PUBLIC, anon;
660681

661682
GRANT EXECUTE ON FUNCTION public.create_workspace(text, text, text, uuid) TO authenticated;
662-
GRANT EXECUTE ON FUNCTION public.update_workspace_document(uuid, uuid, text, text, uuid[], uuid, text, bigint, uuid) TO authenticated;
683+
GRANT EXECUTE ON FUNCTION public.update_workspace_document(uuid, uuid, text, text, uuid[], uuid, boolean, text, bigint, uuid) TO authenticated;
663684
GRANT EXECUTE ON FUNCTION public.change_workspace_access(uuid, text, uuid, bigint, uuid) TO authenticated;
664685
GRANT EXECUTE ON FUNCTION public.change_workspace_state(uuid, text, bigint, uuid) TO authenticated;

0 commit comments

Comments
 (0)