diff --git a/components/LinkList.tsx b/components/LinkList.tsx index 09179715..26874539 100644 --- a/components/LinkList.tsx +++ b/components/LinkList.tsx @@ -1,24 +1,122 @@ -import { LinkAndTags } from "@/types/global"; +import { ExtendedLink } from "@/types/global"; +import { + faFolder, + faArrowUpRightFromSquare, + faCaretRight, + faEllipsis, + faFileImage, + faFilePdf, +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useState } from "react"; export default function ({ link, count, }: { - link: LinkAndTags; + link: ExtendedLink; count: number; }) { + const [archiveLabel, setArchiveLabel] = useState("Archived Formats"); + + const shortendURL = new URL(link.url).host.toLowerCase(); + const formattedDate = new Date(link.createdAt).toLocaleString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }); + return (
- {/*
-

{count + 1}.

-

{link.name}

+
+
+
+

{count + 1}.

+

{link.name}

+
+

{link.title}

+
+
+ +

{link.collection.name}

+
+
+ {link.tags.map((e, i) => ( +

+ # {e.name} +

+ ))} +
+
+
+

{formattedDate}

+ + +
+

{shortendURL}

+ +
+
+
+
+
+ +
+

+ {archiveLabel} +

+ +
setArchiveLabel("Archived Formats")} + > + setArchiveLabel("Screenshot")} + > + + + setArchiveLabel("PDF")} + > + + + setArchiveLabel("Web.archive.org")} + /> +
+
+
-
- {link.tags.map((e, i) => ( -

{e.name}

- ))} -
*/} - {JSON.stringify(link)} + {/*
+
+
+

{JSON.stringify(link)}

*/}
); } diff --git a/components/Navbar.tsx b/components/Navbar.tsx index 7293b68d..10e0ec27 100644 --- a/components/Navbar.tsx +++ b/components/Navbar.tsx @@ -8,7 +8,7 @@ import { faPlus, faFolder, faBox, - faTag, + faHashtag, faBookmark, faMagnifyingGlass, IconDefinition, @@ -49,7 +49,7 @@ export default function () { setPageName(activeTag?.name); } - setPageIcon(faTag); + setPageIcon(faHashtag); } else if (router.route === "/collections") { setPageName("All Collections"); setPageIcon(faBox); diff --git a/components/Sidebar/SidebarItem.tsx b/components/Sidebar/SidebarItem.tsx index d956a3cd..679537dd 100644 --- a/components/Sidebar/SidebarItem.tsx +++ b/components/Sidebar/SidebarItem.tsx @@ -12,9 +12,9 @@ interface SidebarItemProps { export default function ({ text, icon, path }: SidebarItemProps) { return ( -
+
-

{text}

+

{text}

); diff --git a/components/Sidebar/index.tsx b/components/Sidebar/index.tsx index 66d725ee..73b4263c 100644 --- a/components/Sidebar/index.tsx +++ b/components/Sidebar/index.tsx @@ -9,7 +9,7 @@ import { faChevronDown, faFolder, faBox, - faTag, + faHashtag, faBookmark, } from "@fortawesome/free-solid-svg-icons"; import SidebarItem from "./SidebarItem"; @@ -110,7 +110,7 @@ export default function () { ); diff --git a/lib/api/controllers/links/getLinks.ts b/lib/api/controllers/links/getLinks.ts index 9884aac4..bf078609 100644 --- a/lib/api/controllers/links/getLinks.ts +++ b/lib/api/controllers/links/getLinks.ts @@ -24,7 +24,10 @@ export default async function ( ], }, }, - include: { tags: true }, + include: { + tags: true, + collection: true, + }, }); return res.status(200).json({ diff --git a/lib/api/controllers/links/postLink.ts b/lib/api/controllers/links/postLink.ts index c7587256..bf677cdb 100644 --- a/lib/api/controllers/links/postLink.ts +++ b/lib/api/controllers/links/postLink.ts @@ -1,12 +1,13 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { prisma } from "@/lib/api/db"; import { Session } from "next-auth"; -import { LinkAndTags, NewLink } from "@/types/global"; +import { ExtendedLink, NewLink } from "@/types/global"; import { existsSync, mkdirSync } from "fs"; import getTitle from "../../getTitle"; import archive from "../../archive"; -import { Link } from "@prisma/client"; +import { Link, UsersAndCollections } from "@prisma/client"; import AES from "crypto-js/aes"; +import hasAccessToCollection from "@/lib/api/hasAccessToCollection"; export default async function ( req: NextApiRequest, @@ -44,9 +45,8 @@ export default async function ( const checkIfCollectionExists = findCollection?.collections[0]; - if (checkIfCollectionExists) { + if (checkIfCollectionExists) return res.status(400).json({ response: "Collection already exists." }); - } const newCollection = await prisma.collection.create({ data: { @@ -68,6 +68,18 @@ export default async function ( const collectionId = link.collection.id as number; + const collectionIsAccessible = await hasAccessToCollection( + session.user.id, + collectionId + ); + + const memberHasAccess = collectionIsAccessible?.members.some( + (e: UsersAndCollections) => e.userId === session.user.id && e.canCreate + ); + + if (!(collectionIsAccessible?.ownerId === session.user.id || memberHasAccess)) + return res.status(401).json({ response: "Collection is not accessible." }); + const title = await getTitle(link.url); const newLink: Link = await prisma.link.create({ @@ -116,10 +128,10 @@ export default async function ( AES_SECRET ).toString(); - const updatedLink: LinkAndTags = await prisma.link.update({ + const updatedLink: ExtendedLink = await prisma.link.update({ where: { id: newLink.id }, data: { screenshotPath: screenShotHashedPath, pdfPath: pdfHashedPath }, - include: { tags: true }, + include: { tags: true, collection: true }, }); archive(updatedLink.url, updatedLink.collectionId, updatedLink.id); diff --git a/lib/api/hasAccessToCollection.ts b/lib/api/hasAccessToCollection.ts index d7ad8598..49bbc04c 100644 --- a/lib/api/hasAccessToCollection.ts +++ b/lib/api/hasAccessToCollection.ts @@ -1,7 +1,7 @@ import { prisma } from "@/lib/api/db"; export default async (userId: number, collectionId: number) => { - const check: any = await prisma.collection.findFirst({ + const check = await prisma.collection.findFirst({ where: { AND: { id: collectionId, diff --git a/pages/api/routes/links/index.ts b/pages/api/routes/links/index.ts index cd548857..1ded56fa 100644 --- a/pages/api/routes/links/index.ts +++ b/pages/api/routes/links/index.ts @@ -18,9 +18,6 @@ export default async function ( return res.status(401).json({ response: "You must be logged in." }); } - // Check if user is unauthorized to the collection (If isn't owner or doesn't has the required permission...) - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (req.method === "GET") return await getLinks(req, res, session); if (req.method === "POST") return await postLink(req, res, session); } diff --git a/store/links.ts b/store/links.ts index bcdaf8ab..ecde3dd3 100644 --- a/store/links.ts +++ b/store/links.ts @@ -1,11 +1,11 @@ import { create } from "zustand"; -import { LinkAndTags, NewLink } from "@/types/global"; +import { ExtendedLink, NewLink } from "@/types/global"; type LinkSlice = { - links: LinkAndTags[]; + links: ExtendedLink[]; setLinks: () => void; addLink: (linkName: NewLink) => Promise; - updateLink: (link: LinkAndTags) => void; + updateLink: (link: ExtendedLink) => void; removeLink: (linkId: number) => void; }; diff --git a/types/global.ts b/types/global.ts index e9a8de51..3a3fffcd 100644 --- a/types/global.ts +++ b/types/global.ts @@ -1,7 +1,8 @@ -import { Link, Tag } from "@prisma/client"; +import { Collection, Link, Tag } from "@prisma/client"; -export interface LinkAndTags extends Link { +export interface ExtendedLink extends Link { tags: Tag[]; + collection: Collection; } export interface NewLink {