diff options
| author | Dhravya <[email protected]> | 2024-07-01 20:32:50 -0500 |
|---|---|---|
| committer | Dhravya <[email protected]> | 2024-07-01 20:32:50 -0500 |
| commit | 46dfc3b4e7ac5958251401a670c1f4cff49706bb (patch) | |
| tree | f9baefd7dfd4cac46ef09cfc8349131e6235dfe1 /apps | |
| parent | spaces function (diff) | |
| download | supermemory-46dfc3b4e7ac5958251401a670c1f4cff49706bb.tar.xz supermemory-46dfc3b4e7ac5958251401a670c1f4cff49706bb.zip | |
shareable spaces
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/app/(dash)/(memories)/content.tsx | 60 | ||||
| -rw-r--r-- | apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx | 9 | ||||
| -rw-r--r-- | apps/web/app/actions/doers.ts | 44 | ||||
| -rw-r--r-- | apps/web/app/actions/fetchers.ts | 27 | ||||
| -rw-r--r-- | apps/web/migrations/0004_skinny_stature.sql | 6 | ||||
| -rw-r--r-- | apps/web/migrations/meta/0004_snapshot.json | 806 | ||||
| -rw-r--r-- | apps/web/migrations/meta/_journal.json | 7 | ||||
| -rw-r--r-- | apps/web/server/db/schema.ts | 15 |
8 files changed, 957 insertions, 17 deletions
diff --git a/apps/web/app/(dash)/(memories)/content.tsx b/apps/web/app/(dash)/(memories)/content.tsx index 26aed6a5..23bff46b 100644 --- a/apps/web/app/(dash)/(memories)/content.tsx +++ b/apps/web/app/(dash)/(memories)/content.tsx @@ -30,17 +30,20 @@ import { DropdownMenuTrigger, } from "@repo/ui/shadcn/dropdown-menu"; import { Button } from "@repo/ui/shadcn/button"; -import { deleteItem, moveItem } from "@/app/actions/doers"; +import { addUserToSpace, deleteItem, moveItem } from "@/app/actions/doers"; import { toast } from "sonner"; +import { Input } from "@repo/ui/shadcn/input"; export function MemoriesPage({ memoriesAndSpaces, title = "Your Memories", currentSpace, + usersWithAccess, }: { memoriesAndSpaces: { memories: Content[]; spaces: StoredSpace[] }; title?: string; currentSpace?: StoredSpace; + usersWithAccess?: string[]; }) { const [filter, setFilter] = useState("All"); @@ -70,7 +73,6 @@ export function MemoriesPage({ .filter((item) => { if (filter === "All") return true; if (filter === "Spaces" && item.item === "space") { - console.log(item); return true; } if (filter === "Pages") @@ -105,12 +107,55 @@ export function MemoriesPage({ {title} </h2> {currentSpace && ( - <div className="flex gap-4 items-center"> - Space - <div className="flex items-center gap-2 bg-secondary p-2 rounded-xl"> - <Image src={MemoriesIcon} alt="Spaces icon" className="w-3 h-3" /> - <span className="text-[#fff]">{currentSpace.name}</span> + <div className="flex flex-col gap-2"> + <div className="flex gap-4 items-center"> + Space + <div className="flex items-center gap-2 bg-secondary p-2 rounded-xl"> + <Image src={MemoriesIcon} alt="Spaces icon" className="w-3 h-3" /> + <span className="text-[#fff]">{currentSpace.name}</span> + </div> </div> + + {usersWithAccess && usersWithAccess.length > 0 && ( + <div className="flex gap-4 items-center"> + Users with access + <div className="flex gap-2"> + {usersWithAccess.map((user) => ( + <div className="flex items-center gap-2 bg-secondary p-2 rounded-xl"> + <Image + src={UrlIcon} + alt="Spaces icon" + className="w-3 h-3" + /> + <span className="text-[#fff]">{user}</span> + </div> + ))} + </div> + </div> + )} + + <form + action={async (e: FormData) => { + const email = e.get("email")?.toString(); + + if (!email) { + toast.error("Please enter an email"); + return; + } + + const resp = await addUserToSpace(email, currentSpace.id); + + if (resp.success) { + toast.success("User added to space"); + } else { + toast.error("Failed to add user to space"); + } + }} + className="flex gap-2 max-w-xl mt-2" + > + <Input name="email" placeholder="Add user by email" /> + <Button variant="secondary">Add</Button> + </form> </div> )} @@ -268,7 +313,6 @@ function LinkComponent({ onClick={async () => { toast.info("Adding to space..."); - console.log(id, space.id); const response = await moveItem(id, [space.id]); if (response.success) { diff --git a/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx b/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx index 723fb29e..759519cb 100644 --- a/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx +++ b/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx @@ -1,15 +1,24 @@ import { getMemoriesInsideSpace } from "@/app/actions/fetchers"; import { redirect } from "next/navigation"; import MemoriesPage from "../../content"; +import { db } from "@/server/db"; +import { and, eq } from "drizzle-orm"; +import { spacesAccess } from "@/server/db/schema"; async function Page({ params: { spaceid } }: { params: { spaceid: number } }) { const { success, data } = await getMemoriesInsideSpace(spaceid); if (!success ?? !data) return redirect("/home"); + + const hasAccess = await db.query.spacesAccess.findMany({ + where: and(eq(spacesAccess.spaceId, spaceid)), + }); + return ( <MemoriesPage memoriesAndSpaces={{ memories: data.memories, spaces: [] }} title={data.spaces[0]?.name} currentSpace={data.spaces[0]} + usersWithAccess={hasAccess.map((x) => x.userEmail) ?? []} /> ); } diff --git a/apps/web/app/actions/doers.ts b/apps/web/app/actions/doers.ts index 90103092..82263f6e 100644 --- a/apps/web/app/actions/doers.ts +++ b/apps/web/app/actions/doers.ts @@ -9,6 +9,7 @@ import { contentToSpace, sessions, space, + spacesAccess, storedContent, users, } from "../../server/db/schema"; @@ -95,6 +96,47 @@ export const limit = async ( return items <= remainingLimit; }; +export const addUserToSpace = async (userEmail: string, spaceId: number) => { + const data = await auth(); + + if (!data || !data.user || !data.user.id) { + redirect("/signin"); + return { error: "Not authenticated", success: false }; + } + + // We need to make sure that the user owns the space + const spaceData = await db + .select() + .from(space) + .where(and(eq(space.id, spaceId), eq(space.user, data.user.id))) + .all(); + + if (spaceData.length === 0) { + return { + success: false, + error: "You do not own this space", + }; + } + + try { + await db.insert(spacesAccess).values({ + spaceId: spaceId, + userEmail: userEmail, + }); + + revalidatePath("/space/" + spaceId); + + return { + success: true, + }; + } catch (e) { + return { + success: false, + error: (e as Error).message, + }; + } +}; + const getTweetData = async (tweetID: string) => { const url = `https://cdn.syndication.twimg.com/tweet-result?id=${tweetID}&lang=en&features=tfw_timeline_list%3A%3Btfw_follower_count_sunset%3Atrue%3Btfw_tweet_edit_backend%3Aon%3Btfw_refsrc_session%3Aon%3Btfw_fosnr_soft_interventions_enabled%3Aon%3Btfw_show_birdwatch_pivots_enabled%3Aon%3Btfw_show_business_verified_badge%3Aon%3Btfw_duplicate_scribes_to_settings%3Aon%3Btfw_use_profile_image_shape_enabled%3Aon%3Btfw_show_blue_verified_badge%3Aon%3Btfw_legacy_timeline_sunset%3Atrue%3Btfw_show_gov_verified_badge%3Aon%3Btfw_show_business_affiliate_badge%3Aon%3Btfw_tweet_edit_frontend%3Aon&token=4c2mmul6mnh`; @@ -191,8 +233,6 @@ export const createMemory = async (input: { storeToSpaces = []; } - console.log("SAVING URL: ", metadata.baseUrl); - const vectorSaveResponse = await fetch( `${process.env.BACKEND_BASE_URL}/api/add`, { diff --git a/apps/web/app/actions/fetchers.ts b/apps/web/app/actions/fetchers.ts index c33f90d1..1541e4ee 100644 --- a/apps/web/app/actions/fetchers.ts +++ b/apps/web/app/actions/fetchers.ts @@ -1,6 +1,6 @@ "use server"; -import { and, asc, eq, inArray, not, sql } from "drizzle-orm"; +import { and, asc, eq, inArray, not, or, sql } from "drizzle-orm"; import { db } from "../../server/db"; import { canvas, @@ -10,6 +10,7 @@ import { Content, contentToSpace, space, + spacesAccess, storedContent, StoredSpace, users, @@ -90,12 +91,24 @@ export const getMemoriesInsideSpace = async ( .select() .from(storedContent) .where( - inArray( - storedContent.id, - db - .select({ contentId: contentToSpace.contentId }) - .from(contentToSpace) - .where(eq(contentToSpace.spaceId, spaceId)), + and( + inArray( + storedContent.id, + db + .select({ contentId: contentToSpace.contentId }) + .from(contentToSpace) + .where(eq(contentToSpace.spaceId, spaceId)), + ), + or( + eq(storedContent.userId, data.user.id!), + eq( + db + .select({ userId: spacesAccess.userEmail }) + .from(spacesAccess) + .where(eq(spacesAccess.spaceId, spaceId)), + data.user.email, + ), + ), ), ) .execute(); diff --git a/apps/web/migrations/0004_skinny_stature.sql b/apps/web/migrations/0004_skinny_stature.sql new file mode 100644 index 00000000..a0e2d9f6 --- /dev/null +++ b/apps/web/migrations/0004_skinny_stature.sql @@ -0,0 +1,6 @@ +CREATE TABLE `spacesAccess` ( + `spaceId` integer NOT NULL, + `userEmail` text NOT NULL, + PRIMARY KEY(`spaceId`, `userEmail`), + FOREIGN KEY (`spaceId`) REFERENCES `space`(`id`) ON UPDATE no action ON DELETE cascade +); diff --git a/apps/web/migrations/meta/0004_snapshot.json b/apps/web/migrations/meta/0004_snapshot.json new file mode 100644 index 00000000..6ddd66de --- /dev/null +++ b/apps/web/migrations/meta/0004_snapshot.json @@ -0,0 +1,806 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "1c8dc08a-69e1-4d82-b4fc-e6df7b565864", + "prevId": "5d27a673-efd9-47a7-a9f5-84d5cc7d851d", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": ["provider", "providerAccountId"], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {} + }, + "authenticator": { + "name": "authenticator", + "columns": { + "credentialID": { + "name": "credentialID", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialPublicKey": { + "name": "credentialPublicKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialDeviceType": { + "name": "credentialDeviceType", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialBackedUp": { + "name": "credentialBackedUp", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "authenticator_credentialID_unique": { + "name": "authenticator_credentialID_unique", + "columns": ["credentialID"], + "isUnique": true + } + }, + "foreignKeys": { + "authenticator_userId_user_id_fk": { + "name": "authenticator_userId_user_id_fk", + "tableFrom": "authenticator", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "authenticator_userId_credentialID_pk": { + "columns": ["credentialID", "userId"], + "name": "authenticator_userId_credentialID_pk" + } + }, + "uniqueConstraints": {} + }, + "canvas": { + "name": "canvas", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Untitled'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Untitled'" + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "canvas_user_userId": { + "name": "canvas_user_userId", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "canvas_userId_user_id_fk": { + "name": "canvas_userId_user_id_fk", + "tableFrom": "canvas", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "chatHistory": { + "name": "chatHistory", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "threadId": { + "name": "threadId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "question": { + "name": "question", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "answerParts": { + "name": "answerParts", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "answerSources": { + "name": "answerSources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "answerJustification": { + "name": "answerJustification", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "chatHistory_thread_idx": { + "name": "chatHistory_thread_idx", + "columns": ["threadId"], + "isUnique": false + } + }, + "foreignKeys": { + "chatHistory_threadId_chatThread_id_fk": { + "name": "chatHistory_threadId_chatThread_id_fk", + "tableFrom": "chatHistory", + "tableTo": "chatThread", + "columnsFrom": ["threadId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "chatThread": { + "name": "chatThread", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "firstMessage": { + "name": "firstMessage", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "chatThread_user_idx": { + "name": "chatThread_user_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "chatThread_userId_user_id_fk": { + "name": "chatThread_userId_user_id_fk", + "tableFrom": "chatThread", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "contentToSpace": { + "name": "contentToSpace", + "columns": { + "contentId": { + "name": "contentId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "spaceId": { + "name": "spaceId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "contentToSpace_contentId_storedContent_id_fk": { + "name": "contentToSpace_contentId_storedContent_id_fk", + "tableFrom": "contentToSpace", + "tableTo": "storedContent", + "columnsFrom": ["contentId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "contentToSpace_spaceId_space_id_fk": { + "name": "contentToSpace_spaceId_space_id_fk", + "tableFrom": "contentToSpace", + "tableTo": "space", + "columnsFrom": ["spaceId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "contentToSpace_contentId_spaceId_pk": { + "columns": ["contentId", "spaceId"], + "name": "contentToSpace_contentId_spaceId_pk" + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "space": { + "name": "space", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "user": { + "name": "user", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "numItems": { + "name": "numItems", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": { + "space_name_unique": { + "name": "space_name_unique", + "columns": ["name"], + "isUnique": true + }, + "spaces_name_idx": { + "name": "spaces_name_idx", + "columns": ["name"], + "isUnique": false + }, + "spaces_user_idx": { + "name": "spaces_user_idx", + "columns": ["user"], + "isUnique": false + } + }, + "foreignKeys": { + "space_user_user_id_fk": { + "name": "space_user_user_id_fk", + "tableFrom": "space", + "tableTo": "user", + "columnsFrom": ["user"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "spacesAccess": { + "name": "spacesAccess", + "columns": { + "spaceId": { + "name": "spaceId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userEmail": { + "name": "userEmail", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "spacesAccess_spaceId_space_id_fk": { + "name": "spacesAccess_spaceId_space_id_fk", + "tableFrom": "spacesAccess", + "tableTo": "space", + "columnsFrom": ["spaceId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "spacesAccess_spaceId_userEmail_pk": { + "columns": ["spaceId", "userEmail"], + "name": "spacesAccess_spaceId_userEmail_pk" + } + }, + "uniqueConstraints": {} + }, + "storedContent": { + "name": "storedContent", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "savedAt": { + "name": "savedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "baseUrl": { + "name": "baseUrl", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ogImage": { + "name": "ogImage", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'page'" + }, + "image": { + "name": "image", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user": { + "name": "user", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "noteId": { + "name": "noteId", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "storedContent_baseUrl_unique": { + "name": "storedContent_baseUrl_unique", + "columns": ["baseUrl"], + "isUnique": true + }, + "storedContent_url_idx": { + "name": "storedContent_url_idx", + "columns": ["url"], + "isUnique": false + }, + "storedContent_savedAt_idx": { + "name": "storedContent_savedAt_idx", + "columns": ["savedAt"], + "isUnique": false + }, + "storedContent_title_idx": { + "name": "storedContent_title_idx", + "columns": ["title"], + "isUnique": false + }, + "storedContent_user_idx": { + "name": "storedContent_user_idx", + "columns": ["user"], + "isUnique": false + } + }, + "foreignKeys": { + "storedContent_user_user_id_fk": { + "name": "storedContent_user_user_id_fk", + "tableFrom": "storedContent", + "tableTo": "user", + "columnsFrom": ["user"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_email_idx": { + "name": "users_email_idx", + "columns": ["email"], + "isUnique": false + }, + "users_telegram_idx": { + "name": "users_telegram_idx", + "columns": ["telegramId"], + "isUnique": false + }, + "users_id_idx": { + "name": "users_id_idx", + "columns": ["id"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} diff --git a/apps/web/migrations/meta/_journal.json b/apps/web/migrations/meta/_journal.json index 843330f9..c7245478 100644 --- a/apps/web/migrations/meta/_journal.json +++ b/apps/web/migrations/meta/_journal.json @@ -29,6 +29,13 @@ "when": 1719798795179, "tag": "0003_solid_boom_boom", "breakpoints": true + }, + { + "idx": 4, + "version": "6", + "when": 1719882966298, + "tag": "0004_skinny_stature", + "breakpoints": true } ] } diff --git a/apps/web/server/db/schema.ts b/apps/web/server/db/schema.ts index 01cf202d..979b5152 100644 --- a/apps/web/server/db/schema.ts +++ b/apps/web/server/db/schema.ts @@ -161,6 +161,21 @@ export const space = createTable( }), ); +export const spacesAccess = createTable( + "spacesAccess", + { + spaceId: integer("spaceId") + .notNull() + .references(() => space.id, { onDelete: "cascade" }), + userEmail: text("userEmail").notNull(), + }, + (spaceAccess) => ({ + compoundKey: primaryKey({ + columns: [spaceAccess.spaceId, spaceAccess.userEmail], + }), + }), +); + export type StoredContent = Omit<typeof storedContent.$inferSelect, "user">; export type StoredSpace = typeof space.$inferSelect; export type ChachedSpaceContent = StoredContent & { |