chore: move policies to drizzle
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { type Config } from "drizzle-kit";
|
import { type Config } from "drizzle-kit";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
schema: "./src/schema.ts",
|
schema: "./src/schema",
|
||||||
out: "./migrations",
|
out: "./migrations",
|
||||||
dialect: "postgresql",
|
dialect: "postgresql",
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
|
|||||||
347
packages/db/migrations/0008_mature_ravenous.sql
Normal file
347
packages/db/migrations/0008_mature_ravenous.sql
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
ALTER TABLE "board" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "card_activity" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "_card_workspace_members" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "card" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "_card_labels" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "card_comments" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "feedback" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "import" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "label" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "list" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "user" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "workspace_members" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "workspace" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to boards in user's workspace or public boards" ON "board" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
OR visibility = 'public'
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow inserting boards in user's workspace" ON "board" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow updating boards in user's workspace" ON "board" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow deleting boards in user's workspace" ON "board" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to card activity in user's workspace or public boards" ON "card_activity" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow inserting card activity in user's workspace" ON "card_activity" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to card workspace members in user's workspace" ON "_card_workspace_members" AS PERMISSIVE FOR ALL TO "authenticated" USING (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"workspaceMemberId" IN (
|
||||||
|
SELECT wm.id
|
||||||
|
FROM workspace_members wm
|
||||||
|
WHERE wm."workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to cards in user's workspace or public boards" ON "card" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow inserting cards in user's workspace" ON "card" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow updating cards in user's workspace" ON "card" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow deleting cards in user's workspace" ON "card" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to card labels in user's workspace or public boards" ON "_card_labels" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId" AND wm."userId" = auth.uid()
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId" AND wm."userId" = auth.uid()
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow inserting card labels in user's workspace" ON "_card_labels" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow updating card labels in user's workspace" ON "_card_labels" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow deleting card labels in user's workspace" ON "_card_labels" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to card comments in user's workspace or public boards" ON "card_comments" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow inserting comments on cards in user's workspace" ON "card_comments" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow updating own comments" ON "card_comments" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
"createdBy" = auth.uid()
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow deleting own comments" ON "card_comments" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
"createdBy" = auth.uid()
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to user's own imports" ON "import" AS PERMISSIVE FOR ALL TO "authenticated" USING (
|
||||||
|
"createdBy" = auth.uid()
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to labels in user's workspace or public boards" ON "label" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow inserting labels in user's workspace" ON "label" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow updating labels in user's workspace" ON "label" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow deleting labels in user's workspace" ON "label" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow access to lists in user's workspace or public boards" ON "list" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow inserting lists in user's workspace" ON "list" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow updating lists in user's workspace" ON "list" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow deleting lists in user's workspace" ON "list" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow viewing members in user's workspace" ON "user" AS PERMISSIVE FOR SELECT TO "authenticated" USING (
|
||||||
|
id IN (
|
||||||
|
SELECT wm."userId"
|
||||||
|
FROM workspace_members wm
|
||||||
|
WHERE wm."workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow members to view workspace membership" ON "workspace_members" AS PERMISSIVE FOR SELECT TO "authenticated" USING (
|
||||||
|
"userId" = auth.uid() OR
|
||||||
|
is_workspace_member(auth.uid(), "workspaceId")
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow admins to add workspace members" ON "workspace_members" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (
|
||||||
|
is_workspace_admin(auth.uid(), "workspaceId")
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow admins to update workspace members" ON "workspace_members" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
is_workspace_admin(auth.uid(), "workspaceId")
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow admins to remove workspace members" ON "workspace_members" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
is_workspace_admin(auth.uid(), "workspaceId")
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow viewing user's workspaces" ON "workspace" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (
|
||||||
|
CASE
|
||||||
|
WHEN auth.uid() IS NULL THEN
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM board
|
||||||
|
WHERE "workspaceId" = workspace.id
|
||||||
|
AND visibility = 'public'
|
||||||
|
)
|
||||||
|
ELSE
|
||||||
|
id IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
OR "createdBy" = auth.uid()
|
||||||
|
END
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow updating user's workspaces" ON "workspace" AS PERMISSIVE FOR UPDATE TO "authenticated" USING (
|
||||||
|
id IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow deleting user's workspaces" ON "workspace" AS PERMISSIVE FOR DELETE TO "authenticated" USING (
|
||||||
|
id IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
);--> statement-breakpoint
|
||||||
|
CREATE POLICY "Allow authenticated users to create workspaces" ON "workspace" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (true);
|
||||||
2004
packages/db/migrations/meta/0008_snapshot.json
Normal file
2004
packages/db/migrations/meta/0008_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,13 @@
|
|||||||
"when": 1738168854269,
|
"when": 1738168854269,
|
||||||
"tag": "0007_redundant_silver_fox",
|
"tag": "0007_redundant_silver_fox",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 8,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744906695652,
|
||||||
|
"tag": "0008_mature_ravenous",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
"./schema": {
|
"./schema": {
|
||||||
"types": "./dist/schema.d.ts",
|
"types": "./dist/schema.d.ts",
|
||||||
"default": "./src/schema.ts"
|
"default": "./src/schema/index.ts"
|
||||||
},
|
},
|
||||||
"./types/*": {
|
"./types/*": {
|
||||||
"types": "./dist/types/*.d.ts",
|
"types": "./dist/types/*.d.ts",
|
||||||
|
|||||||
@@ -129,604 +129,6 @@ AS $$
|
|||||||
);
|
);
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
alter table "_card_labels" enable row level security;
|
|
||||||
alter table "_card_workspace_members" enable row level security;
|
|
||||||
alter table "_card_activity" enable row level security;
|
|
||||||
alter table "_card_comments" enable row level security;
|
|
||||||
alter table "board" enable row level security;
|
|
||||||
alter table "card" enable row level security;
|
|
||||||
alter table "import" enable row level security;
|
|
||||||
alter table "label" enable row level security;
|
|
||||||
alter table "user" enable row level security;
|
|
||||||
alter table "list" enable row level security;
|
|
||||||
alter table "workspace" enable row level security;
|
|
||||||
alter table "workspace_members" enable row level security;
|
|
||||||
alter table "workspace_slugs" enable row level security;
|
|
||||||
|
|
||||||
|
|
||||||
/* BOARD */
|
|
||||||
CREATE POLICY "Allow access to boards in user's workspace or public boards"
|
|
||||||
ON public.board
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
"workspaceId" IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
OR visibility = 'public'
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow inserting boards in user's workspace"
|
|
||||||
ON public.board
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
"workspaceId" IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow updating boards in user's workspace"
|
|
||||||
ON public.board
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"workspaceId" IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow deleting boards in user's workspace"
|
|
||||||
ON public.board
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"workspaceId" IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow modifications to boards in user's workspace"
|
|
||||||
ON public.board
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"workspaceId" IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* LIST */
|
|
||||||
CREATE POLICY "Allow access to lists in user's workspace or public boards"
|
|
||||||
ON public.list
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
OR b.visibility = 'public'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow inserting lists in user's workspace"
|
|
||||||
ON public.list
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow updating lists in user's workspace"
|
|
||||||
ON public.list
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow deleting lists in user's workspace"
|
|
||||||
ON public.list
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* CARD */
|
|
||||||
CREATE POLICY "Allow access to cards in user's workspace or public boards"
|
|
||||||
ON public.card
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
"listId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM list l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
OR b.visibility = 'public'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow inserting cards in user's workspace"
|
|
||||||
ON public.card
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
"listId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM list l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow updating cards in user's workspace"
|
|
||||||
ON public.card
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"listId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM list l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow deleting cards in user's workspace"
|
|
||||||
ON public.card
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"listId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM list l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* LABEL */
|
|
||||||
CREATE POLICY "Allow access to labels in user's workspace or public boards"
|
|
||||||
ON public.label
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
OR b.visibility = 'public'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow inserting labels in user's workspace"
|
|
||||||
ON public.label
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow updating labels in user's workspace"
|
|
||||||
ON public.label
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow deleting labels in user's workspace"
|
|
||||||
ON public.label
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"boardId" IN (
|
|
||||||
SELECT b.id
|
|
||||||
FROM board b
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* CARD LABELS */
|
|
||||||
CREATE POLICY "Allow access to card labels in user's workspace or public boards"
|
|
||||||
ON public._card_labels
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId" AND wm."userId" = auth.uid()
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
OR b.visibility = 'public'
|
|
||||||
)
|
|
||||||
AND
|
|
||||||
"labelId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM label l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId" AND wm."userId" = auth.uid()
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
OR b.visibility = 'public'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow inserting card labels in user's workspace"
|
|
||||||
ON public._card_labels
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
AND
|
|
||||||
"labelId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM label l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow updating card labels in user's workspace"
|
|
||||||
ON public._card_labels
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
AND
|
|
||||||
"labelId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM label l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow deleting card labels in user's workspace"
|
|
||||||
ON public._card_labels
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
AND
|
|
||||||
"labelId" IN (
|
|
||||||
SELECT l.id
|
|
||||||
FROM label l
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* CARD ACTIVITY */
|
|
||||||
CREATE POLICY "Allow access to card activity in user's workspace or public boards"
|
|
||||||
ON public.card_activity
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
OR b.visibility = 'public'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow inserting card activity in user's workspace"
|
|
||||||
ON public.card_activity
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* CARD COMMENTS */
|
|
||||||
CREATE POLICY "Allow access to card comments in user's workspace or public boards"
|
|
||||||
ON public.card_comments
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
OR b.visibility = 'public'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow inserting comments on cards in user's workspace"
|
|
||||||
ON public.card_comments
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow updating own comments"
|
|
||||||
ON public.card_comments
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"createdBy" = auth.uid()
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow deleting own comments"
|
|
||||||
ON public.card_comments
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"createdBy" = auth.uid()
|
|
||||||
);
|
|
||||||
|
|
||||||
/* CARD WORKSPACE MEMBERS */
|
|
||||||
CREATE POLICY "Allow access to card workspace members in user's workspace"
|
|
||||||
ON public._card_workspace_members
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR ALL
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"cardId" IN (
|
|
||||||
SELECT c.id
|
|
||||||
FROM card c
|
|
||||||
JOIN list l ON c."listId" = l.id
|
|
||||||
JOIN board b ON l."boardId" = b.id
|
|
||||||
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
|
||||||
WHERE wm."userId" = auth.uid()
|
|
||||||
)
|
|
||||||
AND
|
|
||||||
"workspaceMemberId" IN (
|
|
||||||
SELECT wm.id
|
|
||||||
FROM workspace_members wm
|
|
||||||
WHERE wm."workspaceId" IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* USER */
|
|
||||||
CREATE POLICY "Allow viewing members in user's workspace"
|
|
||||||
ON public.user
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
id IN (
|
|
||||||
SELECT wm."userId"
|
|
||||||
FROM workspace_members wm
|
|
||||||
WHERE wm."workspaceId" IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* WORKSPACE */
|
|
||||||
CREATE POLICY "Allow viewing user's workspaces"
|
|
||||||
ON public.workspace
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO anon, authenticated
|
|
||||||
USING (
|
|
||||||
CASE
|
|
||||||
WHEN auth.uid() IS NULL THEN
|
|
||||||
-- For anonymous users, only allow access through public boards
|
|
||||||
EXISTS (
|
|
||||||
SELECT 1
|
|
||||||
FROM board
|
|
||||||
WHERE "workspaceId" = workspace.id
|
|
||||||
AND visibility = 'public'
|
|
||||||
)
|
|
||||||
ELSE
|
|
||||||
-- For authenticated users, allow access to their workspaces
|
|
||||||
id IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
OR "createdBy" = auth.uid()
|
|
||||||
END
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow updating user's workspaces"
|
|
||||||
ON public.workspace
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
id IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow deleting user's workspaces"
|
|
||||||
ON public.workspace
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
id IN (
|
|
||||||
SELECT "workspaceId"
|
|
||||||
FROM workspace_members
|
|
||||||
WHERE "userId" = auth.uid()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow authenticated users to create workspaces"
|
|
||||||
ON public.workspace
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
USING (true);
|
|
||||||
|
|
||||||
/* WORKSPACE MEMBERS */
|
|
||||||
CREATE POLICY "Allow members to view workspace membership"
|
|
||||||
ON public.workspace_members
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR SELECT
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"userId" = auth.uid() OR
|
|
||||||
is_workspace_member(auth.uid(), "workspaceId")
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow admins to add workspace members"
|
|
||||||
ON public.workspace_members
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR INSERT
|
|
||||||
TO authenticated
|
|
||||||
WITH CHECK (
|
|
||||||
is_workspace_admin(auth.uid(), "workspaceId")
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow admins to update workspace members"
|
|
||||||
ON public.workspace_members
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR UPDATE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
is_workspace_admin(auth.uid(), "workspaceId")
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE POLICY "Allow admins to remove workspace members"
|
|
||||||
ON public.workspace_members
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR DELETE
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
is_workspace_admin(auth.uid(), "workspaceId")
|
|
||||||
);
|
|
||||||
|
|
||||||
/* IMPORT */
|
|
||||||
CREATE POLICY "Allow access to user's own imports"
|
|
||||||
ON public.import
|
|
||||||
AS PERMISSIVE
|
|
||||||
FOR ALL
|
|
||||||
TO authenticated
|
|
||||||
USING (
|
|
||||||
"createdBy" = auth.uid()
|
|
||||||
);
|
|
||||||
|
|
||||||
/* BUCKETS */
|
/* BUCKETS */
|
||||||
insert into storage.buckets
|
insert into storage.buckets
|
||||||
(id, name, public)
|
(id, name, public)
|
||||||
|
|||||||
@@ -1,486 +0,0 @@
|
|||||||
import { relations, sql } from "drizzle-orm";
|
|
||||||
import {
|
|
||||||
bigint,
|
|
||||||
bigserial,
|
|
||||||
boolean,
|
|
||||||
index,
|
|
||||||
integer,
|
|
||||||
pgEnum,
|
|
||||||
pgTable,
|
|
||||||
primaryKey,
|
|
||||||
text,
|
|
||||||
timestamp,
|
|
||||||
uniqueIndex,
|
|
||||||
uuid,
|
|
||||||
varchar,
|
|
||||||
} from "drizzle-orm/pg-core";
|
|
||||||
|
|
||||||
export const importSourceEnum = pgEnum("source", ["trello"]);
|
|
||||||
export const importStatusEnum = pgEnum("status", [
|
|
||||||
"started",
|
|
||||||
"success",
|
|
||||||
"failed",
|
|
||||||
]);
|
|
||||||
export const memberRoleEnum = pgEnum("role", ["admin", "member", "guest"]);
|
|
||||||
export const memberStatusEnum = pgEnum("member_status", [
|
|
||||||
"invited",
|
|
||||||
"active",
|
|
||||||
"removed",
|
|
||||||
]);
|
|
||||||
export const activityTypeEnum = pgEnum("card_activity_type", [
|
|
||||||
"card.created",
|
|
||||||
"card.updated.title",
|
|
||||||
"card.updated.description",
|
|
||||||
"card.updated.index",
|
|
||||||
"card.updated.list",
|
|
||||||
"card.updated.label.added",
|
|
||||||
"card.updated.label.removed",
|
|
||||||
"card.updated.member.added",
|
|
||||||
"card.updated.member.removed",
|
|
||||||
"card.updated.comment.added",
|
|
||||||
"card.updated.comment.updated",
|
|
||||||
"card.updated.comment.deleted",
|
|
||||||
"card.archived",
|
|
||||||
]);
|
|
||||||
export const slugTypeEnum = pgEnum("slug_type", ["reserved", "premium"]);
|
|
||||||
export const workspacePlanEnum = pgEnum("workspace_plan", [
|
|
||||||
"free",
|
|
||||||
"pro",
|
|
||||||
"enterprise",
|
|
||||||
]);
|
|
||||||
export const boardVisibilityEnum = pgEnum("board_visibility", [
|
|
||||||
"private",
|
|
||||||
"public",
|
|
||||||
]);
|
|
||||||
|
|
||||||
export const boards = pgTable(
|
|
||||||
"board",
|
|
||||||
{
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
name: varchar("name", { length: 255 }).notNull(),
|
|
||||||
description: text("description"),
|
|
||||||
slug: varchar("slug", { length: 255 }).notNull(),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
deletedAt: timestamp("deletedAt"),
|
|
||||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
|
||||||
importId: bigint("importId", { mode: "number" }).references(
|
|
||||||
() => imports.id,
|
|
||||||
),
|
|
||||||
workspaceId: bigint("workspaceId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
||||||
visibility: boardVisibilityEnum("visibility").notNull().default("private"),
|
|
||||||
},
|
|
||||||
(table) => ({
|
|
||||||
visibilityIndex: index("board_visibility_idx").on(table.visibility),
|
|
||||||
uniqueSlugPerWorkspace: uniqueIndex("unique_slug_per_workspace")
|
|
||||||
.on(table.workspaceId, table.slug)
|
|
||||||
.where(sql`${table.deletedAt} IS NULL`),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const boardsRelations = relations(boards, ({ one, many }) => ({
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [boards.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
lists: many(lists),
|
|
||||||
labels: many(labels),
|
|
||||||
deletedBy: one(users, {
|
|
||||||
fields: [boards.deletedBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
import: one(imports, {
|
|
||||||
fields: [boards.importId],
|
|
||||||
references: [imports.id],
|
|
||||||
}),
|
|
||||||
workspace: one(workspaces, {
|
|
||||||
fields: [boards.workspaceId],
|
|
||||||
references: [workspaces.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const imports = pgTable("import", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
source: importSourceEnum("source").notNull(),
|
|
||||||
status: importStatusEnum("status").notNull(),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const importsRelations = relations(imports, ({ one, many }) => ({
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [imports.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
boards: many(boards),
|
|
||||||
cards: many(cards),
|
|
||||||
lists: many(lists),
|
|
||||||
labels: many(labels),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const labels = pgTable("label", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
name: varchar("name", { length: 255 }).notNull(),
|
|
||||||
colourCode: varchar("colourCode", { length: 12 }),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
boardId: bigint("boardId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => boards.id, { onDelete: "cascade" }),
|
|
||||||
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const labelsRelations = relations(labels, ({ one, many }) => ({
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [labels.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
board: one(boards, {
|
|
||||||
fields: [labels.boardId],
|
|
||||||
references: [boards.id],
|
|
||||||
}),
|
|
||||||
cards: many(cardsToLabels),
|
|
||||||
import: one(imports, {
|
|
||||||
fields: [labels.importId],
|
|
||||||
references: [imports.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const cardsToLabels = pgTable(
|
|
||||||
"_card_labels",
|
|
||||||
{
|
|
||||||
cardId: bigint("cardId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => cards.id),
|
|
||||||
labelId: bigint("labelId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => labels.id, { onDelete: "cascade" }),
|
|
||||||
},
|
|
||||||
(t) => ({
|
|
||||||
pk: primaryKey(t.cardId, t.labelId),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const cardToLabelsRelations = relations(cardsToLabels, ({ one }) => ({
|
|
||||||
card: one(cards, {
|
|
||||||
fields: [cardsToLabels.cardId],
|
|
||||||
references: [cards.id],
|
|
||||||
}),
|
|
||||||
label: one(labels, {
|
|
||||||
fields: [cardsToLabels.labelId],
|
|
||||||
references: [labels.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const cardToWorkspaceMembers = pgTable(
|
|
||||||
"_card_workspace_members",
|
|
||||||
{
|
|
||||||
cardId: bigint("cardId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => cards.id),
|
|
||||||
workspaceMemberId: bigint("workspaceMemberId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => workspaceMembers.id, { onDelete: "cascade" }),
|
|
||||||
},
|
|
||||||
(t) => ({
|
|
||||||
pk: primaryKey(t.cardId, t.workspaceMemberId),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const cardToWorkspaceMembersRelations = relations(
|
|
||||||
cardToWorkspaceMembers,
|
|
||||||
({ one }) => ({
|
|
||||||
card: one(cards, {
|
|
||||||
fields: [cardToWorkspaceMembers.cardId],
|
|
||||||
references: [cards.id],
|
|
||||||
}),
|
|
||||||
member: one(workspaceMembers, {
|
|
||||||
fields: [cardToWorkspaceMembers.workspaceMemberId],
|
|
||||||
references: [workspaceMembers.id],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const lists = pgTable("list", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
name: varchar("name", { length: 255 }).notNull(),
|
|
||||||
index: integer("index").notNull(),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
deletedAt: timestamp("deletedAt"),
|
|
||||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
|
||||||
boardId: bigint("boardId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => boards.id, { onDelete: "cascade" }),
|
|
||||||
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const listsRelations = relations(lists, ({ one, many }) => ({
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [lists.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
board: one(boards, {
|
|
||||||
fields: [lists.boardId],
|
|
||||||
references: [boards.id],
|
|
||||||
}),
|
|
||||||
cards: many(cards),
|
|
||||||
deletedBy: one(users, {
|
|
||||||
fields: [lists.deletedBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
import: one(imports, {
|
|
||||||
fields: [lists.importId],
|
|
||||||
references: [imports.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const cards = pgTable("card", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
title: varchar("title", { length: 255 }).notNull(),
|
|
||||||
description: text("description"),
|
|
||||||
index: integer("index").notNull(),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
deletedAt: timestamp("deletedAt"),
|
|
||||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
|
||||||
listId: bigint("listId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => lists.id, { onDelete: "cascade" }),
|
|
||||||
importId: bigint("importId", { mode: "number" }).references(() => imports.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const cardsRelations = relations(cards, ({ one, many }) => ({
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [cards.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
list: one(lists, {
|
|
||||||
fields: [cards.listId],
|
|
||||||
references: [lists.id],
|
|
||||||
}),
|
|
||||||
deletedBy: one(users, {
|
|
||||||
fields: [cards.deletedBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
labels: many(cardsToLabels),
|
|
||||||
members: many(cardToWorkspaceMembers),
|
|
||||||
import: one(imports, {
|
|
||||||
fields: [cards.importId],
|
|
||||||
references: [imports.id],
|
|
||||||
}),
|
|
||||||
comments: many(comments),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const users = pgTable("user", {
|
|
||||||
id: uuid("id").notNull().primaryKey(),
|
|
||||||
name: varchar("name", { length: 255 }),
|
|
||||||
email: varchar("email", { length: 255 }).notNull().unique(),
|
|
||||||
emailVerified: timestamp("emailVerified", { mode: "date" }),
|
|
||||||
image: varchar("image", { length: 255 }),
|
|
||||||
stripeCustomerId: varchar("stripeCustomerId", { length: 255 }),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const usersRelations = relations(users, ({ many }) => ({
|
|
||||||
boards: many(boards),
|
|
||||||
cards: many(cards),
|
|
||||||
imports: many(imports),
|
|
||||||
lists: many(lists),
|
|
||||||
workspaces: many(workspaces),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const workspaces = pgTable("workspace", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
name: varchar("name", { length: 255 }).notNull(),
|
|
||||||
description: text("description"),
|
|
||||||
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
|
||||||
plan: workspacePlanEnum("plan").notNull().default("free"),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
deletedAt: timestamp("deletedAt"),
|
|
||||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const workspaceRelations = relations(workspaces, ({ one, many }) => ({
|
|
||||||
user: one(users, { fields: [workspaces.createdBy], references: [users.id] }),
|
|
||||||
members: many(workspaceMembers),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const workspaceMembers = pgTable("workspace_members", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
userId: uuid("userId")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
workspaceId: bigint("workspaceId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
||||||
createdBy: uuid("createdBy").notNull(),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
deletedAt: timestamp("deletedAt"),
|
|
||||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
|
||||||
role: memberRoleEnum("role").notNull(),
|
|
||||||
status: memberStatusEnum("status").default("invited").notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const usersToWorkspacesRelations = relations(
|
|
||||||
workspaceMembers,
|
|
||||||
({ one }) => ({
|
|
||||||
addedBy: one(users, {
|
|
||||||
fields: [workspaceMembers.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
deletedBy: one(users, {
|
|
||||||
fields: [workspaceMembers.deletedBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
user: one(users, {
|
|
||||||
fields: [workspaceMembers.userId],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
workspace: one(workspaces, {
|
|
||||||
fields: [workspaceMembers.workspaceId],
|
|
||||||
references: [workspaces.id],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const cardActivities = pgTable("card_activity", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
type: activityTypeEnum("type").notNull(),
|
|
||||||
cardId: bigint("cardId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => cards.id, { onDelete: "cascade" }),
|
|
||||||
fromIndex: integer("fromIndex"),
|
|
||||||
toIndex: integer("toIndex"),
|
|
||||||
fromListId: bigint("fromListId", { mode: "number" }).references(
|
|
||||||
() => lists.id,
|
|
||||||
),
|
|
||||||
toListId: bigint("toListId", { mode: "number" }).references(() => lists.id),
|
|
||||||
labelId: bigint("labelId", { mode: "number" }).references(() => labels.id),
|
|
||||||
workspaceMemberId: bigint("workspaceMemberId", { mode: "number" }).references(
|
|
||||||
() => workspaceMembers.id,
|
|
||||||
),
|
|
||||||
fromTitle: varchar("fromTitle", { length: 255 }),
|
|
||||||
toTitle: varchar("toTitle", { length: 255 }),
|
|
||||||
fromDescription: text("fromDescription"),
|
|
||||||
toDescription: text("toDescription"),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
commentId: bigint("commentId", { mode: "number" }).references(
|
|
||||||
() => comments.id,
|
|
||||||
),
|
|
||||||
fromComment: text("fromComment"),
|
|
||||||
toComment: text("toComment"),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const cardActivitiesRelations = relations(cardActivities, ({ one }) => ({
|
|
||||||
card: one(cards, {
|
|
||||||
fields: [cardActivities.cardId],
|
|
||||||
references: [cards.id],
|
|
||||||
}),
|
|
||||||
fromList: one(lists, {
|
|
||||||
fields: [cardActivities.fromListId],
|
|
||||||
references: [lists.id],
|
|
||||||
}),
|
|
||||||
toList: one(lists, {
|
|
||||||
fields: [cardActivities.toListId],
|
|
||||||
references: [lists.id],
|
|
||||||
}),
|
|
||||||
label: one(labels, {
|
|
||||||
fields: [cardActivities.labelId],
|
|
||||||
references: [labels.id],
|
|
||||||
}),
|
|
||||||
workspaceMember: one(workspaceMembers, {
|
|
||||||
fields: [cardActivities.workspaceMemberId],
|
|
||||||
references: [workspaceMembers.id],
|
|
||||||
}),
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [cardActivities.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const comments = pgTable("card_comments", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
|
||||||
comment: text("comment").notNull(),
|
|
||||||
cardId: bigint("cardId", { mode: "number" })
|
|
||||||
.notNull()
|
|
||||||
.references(() => cards.id, { onDelete: "cascade" }),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
deletedAt: timestamp("deletedAt"),
|
|
||||||
deletedBy: uuid("deletedBy").references(() => users.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const commentsRelations = relations(comments, ({ one }) => ({
|
|
||||||
card: one(cards, {
|
|
||||||
fields: [comments.cardId],
|
|
||||||
references: [cards.id],
|
|
||||||
}),
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [comments.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
deletedBy: one(users, {
|
|
||||||
fields: [comments.deletedBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const slugs = pgTable("workspace_slugs", {
|
|
||||||
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
|
||||||
type: slugTypeEnum("type").notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const feedback = pgTable("feedback", {
|
|
||||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
||||||
feedback: text("feedback").notNull(),
|
|
||||||
createdBy: uuid("createdBy")
|
|
||||||
.notNull()
|
|
||||||
.references(() => users.id),
|
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
|
||||||
updatedAt: timestamp("updatedAt"),
|
|
||||||
url: text("url").notNull(),
|
|
||||||
reviewed: boolean("reviewed").default(false).notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const feedbackRelations = relations(feedback, ({ one }) => ({
|
|
||||||
createdBy: one(users, {
|
|
||||||
fields: [feedback.createdBy],
|
|
||||||
references: [users.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
127
packages/db/src/schema/boards.ts
Normal file
127
packages/db/src/schema/boards.ts
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import { relations, sql } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
bigint,
|
||||||
|
bigserial,
|
||||||
|
index,
|
||||||
|
pgEnum,
|
||||||
|
pgPolicy,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uniqueIndex,
|
||||||
|
uuid,
|
||||||
|
varchar,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { anonRole, authenticatedRole } from "drizzle-orm/supabase";
|
||||||
|
|
||||||
|
import { imports } from "./imports";
|
||||||
|
import { labels } from "./labels";
|
||||||
|
import { lists } from "./lists";
|
||||||
|
import { users } from "./users";
|
||||||
|
import { workspaces } from "./workspaces";
|
||||||
|
|
||||||
|
export const boardVisibilityEnum = pgEnum("board_visibility", [
|
||||||
|
"private",
|
||||||
|
"public",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const boards = pgTable(
|
||||||
|
"board",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
name: varchar("name", { length: 255 }).notNull(),
|
||||||
|
description: text("description"),
|
||||||
|
slug: varchar("slug", { length: 255 }).notNull(),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
deletedAt: timestamp("deletedAt"),
|
||||||
|
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||||
|
importId: bigint("importId", { mode: "number" }).references(
|
||||||
|
() => imports.id,
|
||||||
|
),
|
||||||
|
workspaceId: bigint("workspaceId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
||||||
|
visibility: boardVisibilityEnum("visibility").notNull().default("private"),
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
index("board_visibility_idx").on(table.visibility),
|
||||||
|
uniqueIndex("unique_slug_per_workspace")
|
||||||
|
.on(table.workspaceId, table.slug)
|
||||||
|
.where(sql`${table.deletedAt} IS NULL`),
|
||||||
|
pgPolicy("Allow access to boards in user's workspace or public boards", {
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
OR visibility = 'public'
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow inserting boards in user's workspace", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow updating boards in user's workspace", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow deleting boards in user's workspace", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const boardsRelations = relations(boards, ({ one, many }) => ({
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [boards.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
lists: many(lists),
|
||||||
|
labels: many(labels),
|
||||||
|
deletedBy: one(users, {
|
||||||
|
fields: [boards.deletedBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
import: one(imports, {
|
||||||
|
fields: [boards.importId],
|
||||||
|
references: [imports.id],
|
||||||
|
}),
|
||||||
|
workspace: one(workspaces, {
|
||||||
|
fields: [boards.workspaceId],
|
||||||
|
references: [workspaces.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
504
packages/db/src/schema/cards.ts
Normal file
504
packages/db/src/schema/cards.ts
Normal file
@@ -0,0 +1,504 @@
|
|||||||
|
import { relations, sql } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
bigint,
|
||||||
|
bigserial,
|
||||||
|
integer,
|
||||||
|
pgEnum,
|
||||||
|
pgPolicy,
|
||||||
|
pgTable,
|
||||||
|
primaryKey,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
varchar,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { anonRole, authenticatedRole } from "drizzle-orm/supabase";
|
||||||
|
|
||||||
|
import { imports } from "./imports";
|
||||||
|
import { labels } from "./labels";
|
||||||
|
import { lists } from "./lists";
|
||||||
|
import { users } from "./users";
|
||||||
|
import { workspaceMembers } from "./workspaces";
|
||||||
|
|
||||||
|
export const activityTypeEnum = pgEnum("card_activity_type", [
|
||||||
|
"card.created",
|
||||||
|
"card.updated.title",
|
||||||
|
"card.updated.description",
|
||||||
|
"card.updated.index",
|
||||||
|
"card.updated.list",
|
||||||
|
"card.updated.label.added",
|
||||||
|
"card.updated.label.removed",
|
||||||
|
"card.updated.member.added",
|
||||||
|
"card.updated.member.removed",
|
||||||
|
"card.updated.comment.added",
|
||||||
|
"card.updated.comment.updated",
|
||||||
|
"card.updated.comment.deleted",
|
||||||
|
"card.archived",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const cards = pgTable(
|
||||||
|
"card",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
title: varchar("title", { length: 255 }).notNull(),
|
||||||
|
description: text("description"),
|
||||||
|
index: integer("index").notNull(),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
deletedAt: timestamp("deletedAt"),
|
||||||
|
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||||
|
listId: bigint("listId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => lists.id, { onDelete: "cascade" }),
|
||||||
|
importId: bigint("importId", { mode: "number" }).references(
|
||||||
|
() => imports.id,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy("Allow access to cards in user's workspace or public boards", {
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow inserting cards in user's workspace", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
|
||||||
|
pgPolicy("Allow updating cards in user's workspace", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow deleting cards in user's workspace", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"listId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM list l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const cardsRelations = relations(cards, ({ one, many }) => ({
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [cards.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
list: one(lists, {
|
||||||
|
fields: [cards.listId],
|
||||||
|
references: [lists.id],
|
||||||
|
}),
|
||||||
|
deletedBy: one(users, {
|
||||||
|
fields: [cards.deletedBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
labels: many(cardsToLabels),
|
||||||
|
members: many(cardToWorkspaceMembers),
|
||||||
|
import: one(imports, {
|
||||||
|
fields: [cards.importId],
|
||||||
|
references: [imports.id],
|
||||||
|
}),
|
||||||
|
comments: many(comments),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const cardActivities = pgTable(
|
||||||
|
"card_activity",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
type: activityTypeEnum("type").notNull(),
|
||||||
|
cardId: bigint("cardId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => cards.id, { onDelete: "cascade" }),
|
||||||
|
fromIndex: integer("fromIndex"),
|
||||||
|
toIndex: integer("toIndex"),
|
||||||
|
fromListId: bigint("fromListId", { mode: "number" }).references(
|
||||||
|
() => lists.id,
|
||||||
|
),
|
||||||
|
toListId: bigint("toListId", { mode: "number" }).references(() => lists.id),
|
||||||
|
labelId: bigint("labelId", { mode: "number" }).references(() => labels.id),
|
||||||
|
workspaceMemberId: bigint("workspaceMemberId", {
|
||||||
|
mode: "number",
|
||||||
|
}).references(() => workspaceMembers.id),
|
||||||
|
fromTitle: varchar("fromTitle", { length: 255 }),
|
||||||
|
toTitle: varchar("toTitle", { length: 255 }),
|
||||||
|
fromDescription: text("fromDescription"),
|
||||||
|
toDescription: text("toDescription"),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
commentId: bigint("commentId", { mode: "number" }).references(
|
||||||
|
() => comments.id,
|
||||||
|
),
|
||||||
|
fromComment: text("fromComment"),
|
||||||
|
toComment: text("toComment"),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy(
|
||||||
|
"Allow access to card activity in user's workspace or public boards",
|
||||||
|
{
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
pgPolicy("Allow inserting card activity in user's workspace", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const cardActivitiesRelations = relations(cardActivities, ({ one }) => ({
|
||||||
|
card: one(cards, {
|
||||||
|
fields: [cardActivities.cardId],
|
||||||
|
references: [cards.id],
|
||||||
|
}),
|
||||||
|
fromList: one(lists, {
|
||||||
|
fields: [cardActivities.fromListId],
|
||||||
|
references: [lists.id],
|
||||||
|
}),
|
||||||
|
toList: one(lists, {
|
||||||
|
fields: [cardActivities.toListId],
|
||||||
|
references: [lists.id],
|
||||||
|
}),
|
||||||
|
label: one(labels, {
|
||||||
|
fields: [cardActivities.labelId],
|
||||||
|
references: [labels.id],
|
||||||
|
}),
|
||||||
|
workspaceMember: one(workspaceMembers, {
|
||||||
|
fields: [cardActivities.workspaceMemberId],
|
||||||
|
references: [workspaceMembers.id],
|
||||||
|
}),
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [cardActivities.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const cardsToLabels = pgTable(
|
||||||
|
"_card_labels",
|
||||||
|
{
|
||||||
|
cardId: bigint("cardId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => cards.id),
|
||||||
|
labelId: bigint("labelId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => labels.id, { onDelete: "cascade" }),
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
primaryKey({ columns: [t.cardId, t.labelId] }),
|
||||||
|
pgPolicy(
|
||||||
|
"Allow access to card labels in user's workspace or public boards",
|
||||||
|
{
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId" AND wm."userId" = auth.uid()
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId" AND wm."userId" = auth.uid()
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
pgPolicy("Allow inserting card labels in user's workspace", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow updating card labels in user's workspace", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow deleting card labels in user's workspace", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"labelId" IN (
|
||||||
|
SELECT l.id
|
||||||
|
FROM label l
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const cardToLabelsRelations = relations(cardsToLabels, ({ one }) => ({
|
||||||
|
card: one(cards, {
|
||||||
|
fields: [cardsToLabels.cardId],
|
||||||
|
references: [cards.id],
|
||||||
|
}),
|
||||||
|
label: one(labels, {
|
||||||
|
fields: [cardsToLabels.labelId],
|
||||||
|
references: [labels.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const cardToWorkspaceMembers = pgTable(
|
||||||
|
"_card_workspace_members",
|
||||||
|
{
|
||||||
|
cardId: bigint("cardId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => cards.id),
|
||||||
|
workspaceMemberId: bigint("workspaceMemberId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => workspaceMembers.id, { onDelete: "cascade" }),
|
||||||
|
},
|
||||||
|
(t) => [
|
||||||
|
primaryKey({ columns: [t.cardId, t.workspaceMemberId] }),
|
||||||
|
pgPolicy("Allow access to card workspace members in user's workspace", {
|
||||||
|
for: "all",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
"workspaceMemberId" IN (
|
||||||
|
SELECT wm.id
|
||||||
|
FROM workspace_members wm
|
||||||
|
WHERE wm."workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const cardToWorkspaceMembersRelations = relations(
|
||||||
|
cardToWorkspaceMembers,
|
||||||
|
({ one }) => ({
|
||||||
|
card: one(cards, {
|
||||||
|
fields: [cardToWorkspaceMembers.cardId],
|
||||||
|
references: [cards.id],
|
||||||
|
}),
|
||||||
|
member: one(workspaceMembers, {
|
||||||
|
fields: [cardToWorkspaceMembers.workspaceMemberId],
|
||||||
|
references: [workspaceMembers.id],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const comments = pgTable(
|
||||||
|
"card_comments",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
comment: text("comment").notNull(),
|
||||||
|
cardId: bigint("cardId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => cards.id, { onDelete: "cascade" }),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
deletedAt: timestamp("deletedAt"),
|
||||||
|
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy(
|
||||||
|
"Allow access to card comments in user's workspace or public boards",
|
||||||
|
{
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
pgPolicy("Allow inserting comments on cards in user's workspace", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
"cardId" IN (
|
||||||
|
SELECT c.id
|
||||||
|
FROM card c
|
||||||
|
JOIN list l ON c."listId" = l.id
|
||||||
|
JOIN board b ON l."boardId" = b.id
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow updating own comments", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"createdBy" = auth.uid()
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow deleting own comments", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"createdBy" = auth.uid()
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const commentsRelations = relations(comments, ({ one }) => ({
|
||||||
|
card: one(cards, {
|
||||||
|
fields: [comments.cardId],
|
||||||
|
references: [cards.id],
|
||||||
|
}),
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [comments.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
deletedBy: one(users, {
|
||||||
|
fields: [comments.deletedBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
30
packages/db/src/schema/feedback.ts
Normal file
30
packages/db/src/schema/feedback.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { relations } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
bigserial,
|
||||||
|
boolean,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
import { users } from "./users";
|
||||||
|
|
||||||
|
export const feedback = pgTable("feedback", {
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
feedback: text("feedback").notNull(),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
url: text("url").notNull(),
|
||||||
|
reviewed: boolean("reviewed").default(false).notNull(),
|
||||||
|
}).enableRLS();
|
||||||
|
|
||||||
|
export const feedbackRelations = relations(feedback, ({ one }) => ({
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [feedback.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
59
packages/db/src/schema/imports.ts
Normal file
59
packages/db/src/schema/imports.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { relations, sql } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
bigserial,
|
||||||
|
pgEnum,
|
||||||
|
pgPolicy,
|
||||||
|
pgTable,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
varchar,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { authenticatedRole } from "drizzle-orm/supabase";
|
||||||
|
|
||||||
|
import { boards } from "./boards";
|
||||||
|
import { cards } from "./cards";
|
||||||
|
import { labels } from "./labels";
|
||||||
|
import { lists } from "./lists";
|
||||||
|
import { users } from "./users";
|
||||||
|
|
||||||
|
export const importSourceEnum = pgEnum("source", ["trello"]);
|
||||||
|
export const importStatusEnum = pgEnum("status", [
|
||||||
|
"started",
|
||||||
|
"success",
|
||||||
|
"failed",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const imports = pgTable(
|
||||||
|
"import",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
source: importSourceEnum("source").notNull(),
|
||||||
|
status: importStatusEnum("status").notNull(),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy("Allow access to user's own imports", {
|
||||||
|
for: "all",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"createdBy" = auth.uid()
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const importsRelations = relations(imports, ({ one, many }) => ({
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [imports.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
boards: many(boards),
|
||||||
|
cards: many(cards),
|
||||||
|
lists: many(lists),
|
||||||
|
labels: many(labels),
|
||||||
|
}));
|
||||||
8
packages/db/src/schema/index.ts
Normal file
8
packages/db/src/schema/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export * from "./boards";
|
||||||
|
export * from "./cards";
|
||||||
|
export * from "./feedback";
|
||||||
|
export * from "./imports";
|
||||||
|
export * from "./labels";
|
||||||
|
export * from "./lists";
|
||||||
|
export * from "./users";
|
||||||
|
export * from "./workspaces";
|
||||||
108
packages/db/src/schema/labels.ts
Normal file
108
packages/db/src/schema/labels.ts
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import { relations, sql } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
bigint,
|
||||||
|
bigserial,
|
||||||
|
pgPolicy,
|
||||||
|
pgTable,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
varchar,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { anonRole, authenticatedRole } from "drizzle-orm/supabase";
|
||||||
|
|
||||||
|
import { boards } from "./boards";
|
||||||
|
import { cardsToLabels } from "./cards";
|
||||||
|
import { imports } from "./imports";
|
||||||
|
import { users } from "./users";
|
||||||
|
|
||||||
|
export const labels = pgTable(
|
||||||
|
"label",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
name: varchar("name", { length: 255 }).notNull(),
|
||||||
|
colourCode: varchar("colourCode", { length: 12 }),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
boardId: bigint("boardId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => boards.id, { onDelete: "cascade" }),
|
||||||
|
importId: bigint("importId", { mode: "number" }).references(
|
||||||
|
() => imports.id,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy("Allow access to labels in user's workspace or public boards", {
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow inserting labels in user's workspace", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow updating labels in user's workspace", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow deleting labels in user's workspace", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const labelsRelations = relations(labels, ({ one, many }) => ({
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [labels.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
board: one(boards, {
|
||||||
|
fields: [labels.boardId],
|
||||||
|
references: [boards.id],
|
||||||
|
}),
|
||||||
|
cards: many(cardsToLabels),
|
||||||
|
import: one(imports, {
|
||||||
|
fields: [labels.importId],
|
||||||
|
references: [imports.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
115
packages/db/src/schema/lists.ts
Normal file
115
packages/db/src/schema/lists.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import { relations, sql } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
bigint,
|
||||||
|
bigserial,
|
||||||
|
integer,
|
||||||
|
pgPolicy,
|
||||||
|
pgTable,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
varchar,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { anonRole, authenticatedRole } from "drizzle-orm/supabase";
|
||||||
|
|
||||||
|
import { boards } from "./boards";
|
||||||
|
import { cards } from "./cards";
|
||||||
|
import { imports } from "./imports";
|
||||||
|
import { users } from "./users";
|
||||||
|
|
||||||
|
export const lists = pgTable(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
name: varchar("name", { length: 255 }).notNull(),
|
||||||
|
index: integer("index").notNull(),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
deletedAt: timestamp("deletedAt"),
|
||||||
|
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||||
|
boardId: bigint("boardId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => boards.id, { onDelete: "cascade" }),
|
||||||
|
importId: bigint("importId", { mode: "number" }).references(
|
||||||
|
() => imports.id,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy("Allow access to lists in user's workspace or public boards", {
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
LEFT JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
OR b.visibility = 'public'
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow inserting lists in user's workspace", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow updating lists in user's workspace", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow deleting lists in user's workspace", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"boardId" IN (
|
||||||
|
SELECT b.id
|
||||||
|
FROM board b
|
||||||
|
JOIN workspace_members wm ON b."workspaceId" = wm."workspaceId"
|
||||||
|
WHERE wm."userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const listsRelations = relations(lists, ({ one, many }) => ({
|
||||||
|
createdBy: one(users, {
|
||||||
|
fields: [lists.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
board: one(boards, {
|
||||||
|
fields: [lists.boardId],
|
||||||
|
references: [boards.id],
|
||||||
|
}),
|
||||||
|
cards: many(cards),
|
||||||
|
deletedBy: one(users, {
|
||||||
|
fields: [lists.deletedBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
import: one(imports, {
|
||||||
|
fields: [lists.importId],
|
||||||
|
references: [imports.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
75
packages/db/src/schema/users.ts
Normal file
75
packages/db/src/schema/users.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { relations, sql } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
pgPolicy,
|
||||||
|
pgTable,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
varchar,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { authenticatedRole } from "drizzle-orm/supabase";
|
||||||
|
|
||||||
|
import { boards } from "./boards";
|
||||||
|
import { cards } from "./cards";
|
||||||
|
import { imports } from "./imports";
|
||||||
|
import { lists } from "./lists";
|
||||||
|
import { workspaceMembers, workspaces } from "./workspaces";
|
||||||
|
|
||||||
|
export const users = pgTable(
|
||||||
|
"user",
|
||||||
|
{
|
||||||
|
id: uuid("id").notNull().primaryKey(),
|
||||||
|
name: varchar("name", { length: 255 }),
|
||||||
|
email: varchar("email", { length: 255 }).notNull().unique(),
|
||||||
|
emailVerified: timestamp("emailVerified", { mode: "date" }),
|
||||||
|
image: varchar("image", { length: 255 }),
|
||||||
|
stripeCustomerId: varchar("stripeCustomerId", { length: 255 }),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy("Allow viewing members in user's workspace", {
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
id IN (
|
||||||
|
SELECT wm."userId"
|
||||||
|
FROM workspace_members wm
|
||||||
|
WHERE wm."workspaceId" IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const usersRelations = relations(users, ({ many }) => ({
|
||||||
|
boards: many(boards),
|
||||||
|
cards: many(cards),
|
||||||
|
imports: many(imports),
|
||||||
|
lists: many(lists),
|
||||||
|
workspaces: many(workspaces),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const usersToWorkspacesRelations = relations(
|
||||||
|
workspaceMembers,
|
||||||
|
({ one }) => ({
|
||||||
|
addedBy: one(users, {
|
||||||
|
fields: [workspaceMembers.createdBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
deletedBy: one(users, {
|
||||||
|
fields: [workspaceMembers.deletedBy],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
user: one(users, {
|
||||||
|
fields: [workspaceMembers.userId],
|
||||||
|
references: [users.id],
|
||||||
|
}),
|
||||||
|
workspace: one(workspaces, {
|
||||||
|
fields: [workspaceMembers.workspaceId],
|
||||||
|
references: [workspaces.id],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
168
packages/db/src/schema/workspaces.ts
Normal file
168
packages/db/src/schema/workspaces.ts
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import { relations, sql } from "drizzle-orm";
|
||||||
|
import {
|
||||||
|
bigint,
|
||||||
|
bigserial,
|
||||||
|
pgEnum,
|
||||||
|
pgPolicy,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
varchar,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { anonRole, authenticatedRole } from "drizzle-orm/supabase";
|
||||||
|
|
||||||
|
import { users } from "./users";
|
||||||
|
|
||||||
|
export const memberRoleEnum = pgEnum("role", ["admin", "member", "guest"]);
|
||||||
|
export const memberStatusEnum = pgEnum("member_status", [
|
||||||
|
"invited",
|
||||||
|
"active",
|
||||||
|
"removed",
|
||||||
|
]);
|
||||||
|
export const slugTypeEnum = pgEnum("slug_type", ["reserved", "premium"]);
|
||||||
|
export const workspacePlanEnum = pgEnum("workspace_plan", [
|
||||||
|
"free",
|
||||||
|
"pro",
|
||||||
|
"enterprise",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const workspaces = pgTable(
|
||||||
|
"workspace",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
name: varchar("name", { length: 255 }).notNull(),
|
||||||
|
description: text("description"),
|
||||||
|
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
||||||
|
plan: workspacePlanEnum("plan").notNull().default("free"),
|
||||||
|
createdBy: uuid("createdBy")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
deletedAt: timestamp("deletedAt"),
|
||||||
|
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy("Allow viewing user's workspaces", {
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole, anonRole],
|
||||||
|
using: sql`
|
||||||
|
CASE
|
||||||
|
WHEN auth.uid() IS NULL THEN
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM board
|
||||||
|
WHERE "workspaceId" = workspace.id
|
||||||
|
AND visibility = 'public'
|
||||||
|
)
|
||||||
|
ELSE
|
||||||
|
id IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
OR "createdBy" = auth.uid()
|
||||||
|
END
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow updating user's workspaces", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
id IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow deleting user's workspaces", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
id IN (
|
||||||
|
SELECT "workspaceId"
|
||||||
|
FROM workspace_members
|
||||||
|
WHERE "userId" = auth.uid()
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow authenticated users to create workspaces", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`true`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const workspaceRelations = relations(workspaces, ({ one, many }) => ({
|
||||||
|
user: one(users, { fields: [workspaces.createdBy], references: [users.id] }),
|
||||||
|
members: many(workspaceMembers),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const workspaceMembers = pgTable(
|
||||||
|
"workspace_members",
|
||||||
|
{
|
||||||
|
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||||
|
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||||
|
userId: uuid("userId")
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id),
|
||||||
|
workspaceId: bigint("workspaceId", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
||||||
|
createdBy: uuid("createdBy").notNull(),
|
||||||
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp("updatedAt"),
|
||||||
|
deletedAt: timestamp("deletedAt"),
|
||||||
|
deletedBy: uuid("deletedBy").references(() => users.id),
|
||||||
|
role: memberRoleEnum("role").notNull(),
|
||||||
|
status: memberStatusEnum("status").default("invited").notNull(),
|
||||||
|
},
|
||||||
|
() => [
|
||||||
|
pgPolicy("Allow members to view workspace membership", {
|
||||||
|
for: "select",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
"userId" = auth.uid() OR
|
||||||
|
is_workspace_member(auth.uid(), "workspaceId")
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow admins to add workspace members", {
|
||||||
|
for: "insert",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
withCheck: sql`
|
||||||
|
is_workspace_admin(auth.uid(), "workspaceId")
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow admins to update workspace members", {
|
||||||
|
for: "update",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
is_workspace_admin(auth.uid(), "workspaceId")
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
pgPolicy("Allow admins to remove workspace members", {
|
||||||
|
for: "delete",
|
||||||
|
as: "permissive",
|
||||||
|
to: [authenticatedRole],
|
||||||
|
using: sql`
|
||||||
|
is_workspace_admin(auth.uid(), "workspaceId")
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
).enableRLS();
|
||||||
|
|
||||||
|
export const slugs = pgTable("workspace_slugs", {
|
||||||
|
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
||||||
|
type: slugTypeEnum("type").notNull(),
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user