Skip to content

Commit

Permalink
[refactor] Extract the bookmark model to be a high level model to sup…
Browse files Browse the repository at this point in the history
…port other type of bookmarks
  • Loading branch information
MohamedBassem committed Feb 9, 2024
1 parent c5bfa50 commit 08a5694
Show file tree
Hide file tree
Showing 20 changed files with 330 additions and 242 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"devDependencies": {
"@types/node": "^20",
"es-errors": "^1.3.0",
"eslint": "^8.56.0",
"eslint-config-next": "14.1.0",
"prettier": "3.2.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Warnings:
- You are about to drop the `BookmarkedLinkDetails` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `TagsOnLinks` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the column `createdAt` on the `BookmarkedLink` table. All the data in the column will be lost.
- You are about to drop the column `userId` on the `BookmarkedLink` table. All the data in the column will be lost.
*/
-- DropIndex
DROP INDEX "TagsOnLinks_linkId_tagId_key";

-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "BookmarkedLinkDetails";
PRAGMA foreign_keys=on;

-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "TagsOnLinks";
PRAGMA foreign_keys=on;

-- CreateTable
CREATE TABLE "Bookmark" (
"id" TEXT NOT NULL PRIMARY KEY,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"archived" BOOLEAN NOT NULL DEFAULT false,
"favourited" BOOLEAN NOT NULL DEFAULT false,
"userId" TEXT NOT NULL,
CONSTRAINT "Bookmark_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);

-- CreateTable
CREATE TABLE "TagsOnBookmarks" (
"bookmarkId" TEXT NOT NULL,
"tagId" TEXT NOT NULL,
"attachedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"attachedBy" TEXT NOT NULL,
CONSTRAINT "TagsOnBookmarks_bookmarkId_fkey" FOREIGN KEY ("bookmarkId") REFERENCES "Bookmark" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "TagsOnBookmarks_tagId_fkey" FOREIGN KEY ("tagId") REFERENCES "BookmarkTags" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);

-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_BookmarkedLink" (
"id" TEXT NOT NULL PRIMARY KEY,
"url" TEXT NOT NULL,
"title" TEXT,
"description" TEXT,
"imageUrl" TEXT,
"favicon" TEXT,
"crawledAt" DATETIME,
CONSTRAINT "BookmarkedLink_id_fkey" FOREIGN KEY ("id") REFERENCES "Bookmark" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_BookmarkedLink" ("id", "url") SELECT "id", "url" FROM "BookmarkedLink";
DROP TABLE "BookmarkedLink";
ALTER TABLE "new_BookmarkedLink" RENAME TO "BookmarkedLink";
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;

-- CreateIndex
CREATE UNIQUE INDEX "TagsOnBookmarks_bookmarkId_tagId_key" ON "TagsOnBookmarks"("bookmarkId", "tagId");
54 changes: 31 additions & 23 deletions packages/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ model Session {
}

model User {
id String @id @default(cuid())
id String @id @default(cuid())
name String?
email String? @unique
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
links BookmarkedLink[]
tags BookmarkTags[]
bookmarks Bookmark[]
}

model VerificationToken {
Expand All @@ -57,28 +57,34 @@ model VerificationToken {
@@unique([identifier, token])
}

model BookmarkedLink {
id String @id @default(cuid())
url String
createdAt DateTime @default(now())
model Bookmark {
id String @id @default(cuid())
createdAt DateTime @default(now())
archived Boolean @default(false)
favourited Boolean @default(false)
userId String
userId String
// Content relation
link BookmarkedLink?
details BookmarkedLinkDetails?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tags TagsOnLinks[]
// Other relations
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tags TagsOnBookmarks[]
}

model BookmarkedLinkDetails {
id String @id
model BookmarkedLink {
id String @id
url String
// Crawled info
title String?
description String?
imageUrl String?
favicon String?
createdAt DateTime @default(now())
crawledAt DateTime?
link BookmarkedLink @relation(fields: [id], references: [id], onDelete: Cascade)
// Relations
parentBookmark Bookmark @relation(fields: [id], references: [id], onDelete: Cascade)
}

model BookmarkTags {
Expand All @@ -88,18 +94,20 @@ model BookmarkTags {
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
attachedLinks TagsOnLinks[]
// Relations
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
bookmarks TagsOnBookmarks[]
}

model TagsOnLinks {
link BookmarkedLink @relation(fields: [linkId], references: [id], onDelete: Cascade)
linkId String
model TagsOnBookmarks {
bookmark Bookmark @relation(fields: [bookmarkId], references: [id], onDelete: Cascade)
bookmarkId String
tag BookmarkTags @relation(fields: [tagId], references: [id], onDelete: Cascade)
tagId String
attachedAt DateTime @default(now())
attachedAt DateTime @default(now())
attachedBy String // "human" or "ai" (if only prisma sqlite supported enums)
@@unique([linkId, tagId])
@@unique([bookmarkId, tagId])
}
4 changes: 2 additions & 2 deletions packages/shared/queues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const queueConnectionDetails = {

// Link Crawler
export const zCrawlLinkRequestSchema = z.object({
linkId: z.string(),
bookmarkId: z.string(),
url: z.string().url(),
});
export type ZCrawlLinkRequest = z.infer<typeof zCrawlLinkRequestSchema>;
Expand All @@ -20,7 +20,7 @@ export const LinkCrawlerQueue = new Queue<ZCrawlLinkRequest, void>(

// OpenAI Worker
export const zOpenAIRequestSchema = z.object({
linkId: z.string(),
bookmarkId: z.string(),
});
export type ZOpenAIRequest = z.infer<typeof zOpenAIRequestSchema>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { authOptions } from "@/lib/auth";
import { unbookmarkLink } from "@/lib/services/links";
import { deleteBookmark } from "@/lib/services/bookmarks";
import { Prisma } from "@remember/db";

import { getServerSession } from "next-auth";
import { NextRequest } from "next/server";

export async function DELETE(
_request: NextRequest,
{ params }: { params: { linkId: string } },
{ params }: { params: { bookmarkId: string } },
) {
// TODO: We probably should be using an API key here instead of the session;
const session = await getServerSession(authOptions);
Expand All @@ -16,7 +16,7 @@ export async function DELETE(
}

try {
await unbookmarkLink(params.linkId, session.user.id);
await deleteBookmark(params.bookmarkId, session.user.id);
} catch (e: unknown) {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { authOptions } from "@/lib/auth";
import { bookmarkLink, getLinks } from "@/lib/services/links";
import { bookmarkLink, getBookmarks } from "@/lib/services/bookmarks";

import {
zNewBookmarkedLinkRequestSchema,
ZGetLinksResponse,
ZBookmarkedLink,
} from "@/lib/types/api/links";
zNewBookmarkRequestSchema,
ZGetBookmarksResponse,
ZBookmark,
} from "@/lib/types/api/bookmarks";
import { getServerSession } from "next-auth";
import { NextRequest, NextResponse } from "next/server";

Expand All @@ -16,9 +16,7 @@ export async function POST(request: NextRequest) {
return new Response(null, { status: 401 });
}

const linkRequest = zNewBookmarkedLinkRequestSchema.safeParse(
await request.json(),
);
const linkRequest = zNewBookmarkRequestSchema.safeParse(await request.json());

if (!linkRequest.success) {
return NextResponse.json(
Expand All @@ -29,9 +27,9 @@ export async function POST(request: NextRequest) {
);
}

const link = await bookmarkLink(linkRequest.data.url, session.user.id);
const bookmark = await bookmarkLink(linkRequest.data.url, session.user.id);

let response: ZBookmarkedLink = { ...link };
let response: ZBookmark = { ...bookmark };
return NextResponse.json(response, { status: 201 });
}

Expand All @@ -42,8 +40,8 @@ export async function GET() {
return new Response(null, { status: 401 });
}

const links = await getLinks(session.user.id);
const bookmarks = await getBookmarks(session.user.id);

let response: ZGetLinksResponse = { links };
let response: ZGetBookmarksResponse = { bookmarks };
return NextResponse.json(response);
}
27 changes: 27 additions & 0 deletions packages/web/app/dashboard/bookmarks/components/BookmarksGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";
import { authOptions } from "@/lib/auth";
import { getBookmarks } from "@/lib/services/bookmarks";
import LinkCard from "./LinkCard";
import { ZBookmark } from "@/lib/types/api/bookmarks";

function renderBookmark(bookmark: ZBookmark) {
switch (bookmark.content.type) {
case "link":
return <LinkCard key={bookmark.id} bookmark={bookmark} />;
}
}

export default async function BookmarksGrid() {
const session = await getServerSession(authOptions);
if (!session) {
redirect("/");
}
const bookmarks = await getBookmarks(session.user.id);

return (
<div className="container grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
{bookmarks.map((b) => renderBookmark(b))}
</div>
);
}
15 changes: 8 additions & 7 deletions packages/web/app/dashboard/bookmarks/components/LinkCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from "@/components/ui/imageCard";
import { useToast } from "@/components/ui/use-toast";
import APIClient from "@/lib/api";
import { ZBookmarkedLink } from "@/lib/types/api/links";
import { ZBookmark } from "@/lib/types/api/bookmarks";
import { MoreHorizontal, Trash2 } from "lucide-react";
import Link from "next/link";
import { useRouter } from "next/navigation";
Expand All @@ -26,7 +26,7 @@ export function LinkOptions({ linkId }: { linkId: string }) {
const router = useRouter();

const unbookmarkLink = async () => {
let [_, error] = await APIClient.unbookmarkLink(linkId);
let [_, error] = await APIClient.deleteBookmark(linkId);

if (error) {
toast({
Expand Down Expand Up @@ -59,23 +59,24 @@ export function LinkOptions({ linkId }: { linkId: string }) {
);
}

export default function LinkCard({ link }: { link: ZBookmarkedLink }) {
export default function LinkCard({ bookmark }: { bookmark: ZBookmark }) {
const link = bookmark.content;
const parsedUrl = new URL(link.url);

return (
<ImageCard
className={
"bg-gray-50 duration-300 ease-in border border-grey-100 hover:transition-all hover:border-blue-300"
}
image={link.details?.imageUrl ?? undefined}
image={link?.imageUrl ?? undefined}
>
<ImageCardTitle>
<Link className="line-clamp-3" href={link.url}>
{link.details?.title ?? parsedUrl.host}
{link?.title ?? parsedUrl.host}
</Link>
</ImageCardTitle>
<ImageCardBody className="py-2 overflow-clip">
{link.tags.map((t) => (
{bookmark.tags.map((t) => (
<Badge
variant="default"
className="bg-gray-300 text-gray-500"
Expand All @@ -92,7 +93,7 @@ export default function LinkCard({ link }: { link: ZBookmarkedLink }) {
{parsedUrl.host}
</Link>
</div>
<LinkOptions linkId={link.id} />
<LinkOptions linkId={bookmark.id} />
</div>
</ImageCardFooter>
</ImageCard>
Expand Down
21 changes: 0 additions & 21 deletions packages/web/app/dashboard/bookmarks/components/LinksGrid.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions packages/web/app/dashboard/bookmarks/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import AddLink from "./components/AddLink";
import LinksGrid from "./components/LinksGrid";
import BookmarksGrid from "./components/BookmarksGrid";
import type { Metadata } from "next";

export const metadata: Metadata = {
Expand All @@ -13,7 +13,7 @@ export default async function Bookmarks() {
<AddLink />
</div>
<div>
<LinksGrid />
<BookmarksGrid />
</div>
</div>
);
Expand Down
Loading

0 comments on commit 08a5694

Please sign in to comment.