mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 13:24:55 +01:00
feat: add private project access
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
df05b1a968
commit
c761282d76
29 files changed
+1197
-29
No files matched your search
@@ -0,0 +1,41 @@
|
||||
ALTER TABLE "projects" ADD COLUMN IF NOT EXISTS "visibility" text DEFAULT 'open' NOT NULL;
|
||||
ALTER TABLE "projects" ADD COLUMN IF NOT EXISTS "personal_owner_user_id" text;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "projects"
|
||||
ADD CONSTRAINT "projects_visibility_check" CHECK ("visibility" IN ('open', 'private'));
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "projects_company_personal_owner_uq"
|
||||
ON "projects" USING btree ("company_id", "personal_owner_user_id")
|
||||
WHERE "personal_owner_user_id" IS NOT NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "project_access_members" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"company_id" uuid NOT NULL,
|
||||
"project_id" uuid NOT NULL,
|
||||
"subject_type" text NOT NULL,
|
||||
"subject_id" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "project_access_members_subject_type_check" CHECK ("subject_type" IN ('user', 'agent'))
|
||||
);
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "project_access_members"
|
||||
ADD CONSTRAINT "project_access_members_company_id_companies_id_fk"
|
||||
FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "project_access_members"
|
||||
ADD CONSTRAINT "project_access_members_project_id_projects_id_fk"
|
||||
FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "project_access_members_project_subject_uq"
|
||||
ON "project_access_members" USING btree ("project_id", "subject_type", "subject_id");
|
||||
CREATE INDEX IF NOT EXISTS "project_access_members_subject_lookup_idx"
|
||||
ON "project_access_members" USING btree ("company_id", "subject_type", "subject_id", "project_id");
|
||||
@@ -1387,6 +1387,13 @@
|
||||
"when": 1785628800000,
|
||||
"tag": "0199_heartbeat_run_issue_privacy",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 200,
|
||||
"version": "7",
|
||||
"when": 1785715200000,
|
||||
"tag": "0200_private_projects",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -24,6 +24,7 @@ export { agentTaskSessions } from "./agent_task_sessions.js";
|
||||
export { agentWakeupRequests } from "./agent_wakeup_requests.js";
|
||||
export { projects } from "./projects.js";
|
||||
export { projectMemberships } from "./project_memberships.js";
|
||||
export { projectAccessMembers } from "./project_access_members.js";
|
||||
export { documentMemberships } from "./document_memberships.js";
|
||||
export { projectWorkspaces } from "./project_workspaces.js";
|
||||
export { executionWorkspaces } from "./execution_workspaces.js";
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { sql } from "drizzle-orm";
|
||||
import { check, index, pgTable, text, timestamp, uniqueIndex, uuid } from "drizzle-orm/pg-core";
|
||||
import { companies } from "./companies.js";
|
||||
import { projects } from "./projects.js";
|
||||
|
||||
/** Authorization membership for private projects; unrelated to sidebar project_memberships. */
|
||||
export const projectAccessMembers = pgTable(
|
||||
"project_access_members",
|
||||
{
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
companyId: uuid("company_id").notNull().references(() => companies.id, { onDelete: "cascade" }),
|
||||
projectId: uuid("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
||||
subjectType: text("subject_type").notNull(),
|
||||
subjectId: text("subject_id").notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||
},
|
||||
(table) => ({
|
||||
subjectTypeCheck: check(
|
||||
"project_access_members_subject_type_check",
|
||||
sql`${table.subjectType} in ('user', 'agent')`,
|
||||
),
|
||||
projectSubjectUq: uniqueIndex("project_access_members_project_subject_uq").on(
|
||||
table.projectId,
|
||||
table.subjectType,
|
||||
table.subjectId,
|
||||
),
|
||||
subjectLookupIdx: index("project_access_members_subject_lookup_idx").on(
|
||||
table.companyId,
|
||||
table.subjectType,
|
||||
table.subjectId,
|
||||
table.projectId,
|
||||
),
|
||||
}),
|
||||
);
|
||||
@@ -1,4 +1,5 @@
|
||||
import { pgTable, uuid, text, timestamp, date, index, jsonb } from "drizzle-orm/pg-core";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { pgTable, uuid, text, timestamp, date, index, jsonb, check, uniqueIndex } from "drizzle-orm/pg-core";
|
||||
import type { AgentEnvConfig } from "@paperclipai/shared";
|
||||
import { companies } from "./companies.js";
|
||||
import { goals } from "./goals.js";
|
||||
@@ -12,6 +13,8 @@ export const projects = pgTable(
|
||||
goalId: uuid("goal_id").references(() => goals.id),
|
||||
name: text("name").notNull(),
|
||||
description: text("description"),
|
||||
visibility: text("visibility").notNull().default("open"),
|
||||
personalOwnerUserId: text("personal_owner_user_id"),
|
||||
status: text("status").notNull().default("backlog"),
|
||||
leadAgentId: uuid("lead_agent_id").references(() => agents.id),
|
||||
targetDate: date("target_date"),
|
||||
@@ -27,5 +30,9 @@ export const projects = pgTable(
|
||||
},
|
||||
(table) => ({
|
||||
companyIdx: index("projects_company_idx").on(table.companyId),
|
||||
visibilityCheck: check("projects_visibility_check", sql`${table.visibility} in ('open', 'private')`),
|
||||
personalOwnerUq: uniqueIndex("projects_company_personal_owner_uq")
|
||||
.on(table.companyId, table.personalOwnerUserId)
|
||||
.where(sql`${table.personalOwnerUserId} is not null`),
|
||||
}),
|
||||
);
|
||||
Reference in new issue
Block a user