diff --git a/prisma/migrations/20250105172446_add_liked_posts/migration.sql b/prisma/migrations/20250105172446_add_liked_posts/migration.sql new file mode 100644 index 0000000..54cbaeb --- /dev/null +++ b/prisma/migrations/20250105172446_add_liked_posts/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "likedPosts" TEXT[]; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 55065e2..4b71549 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -17,6 +17,7 @@ model User { id String @id @default(cuid()) username String @unique hashed_password String + likedPosts String[] sessions Session[] posts Post[] } diff --git a/src/app/(public)/page.tsx b/src/app/(public)/page.tsx index b73bb7d..8b20fbb 100644 --- a/src/app/(public)/page.tsx +++ b/src/app/(public)/page.tsx @@ -5,15 +5,25 @@ import Link from 'next/link'; export default async function Home() { const posts = await prisma.post.findMany({ take: 30 }); return ( -
+

This is nextbooru

The simplest and most modern booru software.

-

(very unstable and not feature complete!)

+

+ (very unstable and not feature complete!) +

{posts.map((post) => (
- {''} + {''}
))} diff --git a/src/app/(public)/post/[id]/page.tsx b/src/app/(public)/post/[id]/page.tsx index fa86bde..782581e 100644 --- a/src/app/(public)/post/[id]/page.tsx +++ b/src/app/(public)/post/[id]/page.tsx @@ -1,12 +1,15 @@ +import LikePost from '@/components/app/LikePost/LikePost'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; +import { validateRequest } from '@/lib/auth'; import prisma from '@/lib/db'; -import { Heart, Download, Flag, MessageSquare, Link, User, Calendar } from 'lucide-react'; +import { Download, Flag, MessageSquare, User, Calendar } from 'lucide-react'; import Image from 'next/image'; export default async function Page({ params }: { params: Promise<{ id: string }> }) { + const { user } = await validateRequest(); const { id } = await params; const post = await prisma.post.findUnique({ where: { id }, include: { author: true } }); if (!post) { @@ -31,9 +34,7 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
- + + ); +} + +interface Props { + id: string; + liked: boolean; +} diff --git a/src/lib/auth/index.ts b/src/lib/auth/index.ts index e2d0d18..0ff2b4a 100644 --- a/src/lib/auth/index.ts +++ b/src/lib/auth/index.ts @@ -1,71 +1,64 @@ -import { PrismaAdapter } from "@lucia-auth/adapter-prisma"; -import { Lucia, Session, User } from "lucia"; -import prisma from "../db"; -import { cache } from "react"; -import { cookies } from "next/headers"; +import { PrismaAdapter } from '@lucia-auth/adapter-prisma'; +import { Lucia } from 'lucia'; +import prisma from '../db'; +import { cache } from 'react'; +import { cookies } from 'next/headers'; const adapter = new PrismaAdapter(prisma.session, prisma.user); export const lucia = new Lucia(adapter, { - sessionCookie: { - // this sets cookies with super long expiration - // since Next.js doesn't allow Lucia to extend cookie expiration when rendering pages - expires: false, - attributes: { - // set to `true` when using HTTPS - secure: process.env.NODE_ENV === "production" - } - }, - getUserAttributes: (attributes) => { - return { - username: attributes.username - }; - } + sessionCookie: { + // this sets cookies with super long expiration + // since Next.js doesn't allow Lucia to extend cookie expiration when rendering pages + expires: false, + attributes: { + // set to `true` when using HTTPS + secure: process.env.NODE_ENV === 'production', + }, + }, + getUserAttributes: (attributes) => { + return { + username: attributes.username, + likedPosts: attributes.likedPosts, + }; + }, }); export const validateRequest = cache(async () => { - const sessionId = (await cookies()).get(lucia.sessionCookieName)?.value ?? null - - if (!sessionId) - return { - user: null, - session: null, - } - - const { user, session } = await lucia.validateSession(sessionId) - try { - if (session && session.fresh) { - const sessionCookie = lucia.createSessionCookie(session.id) - (await cookies()).set( - sessionCookie.name, - sessionCookie.value, - sessionCookie.attributes - ) - } - if (!session) { - const sessionCookie = lucia.createBlankSessionCookie() - (await cookies()).set( - sessionCookie.name, - sessionCookie.value, - sessionCookie.attributes - ) - } - } catch { - // Next.js throws error attempting to set cookies when rendering page - } - return { - user, - session, - } - }) + const sessionId = (await cookies()).get(lucia.sessionCookieName)?.value ?? null; + if (!sessionId) + return { + user: null, + session: null, + }; -declare module "lucia" { - interface Register { - Lucia: typeof lucia; - DatabaseUserAttributes: DatabaseUserAttributes; - } + const { user, session } = await lucia.validateSession(sessionId); + try { + if (session && session.fresh) { + const sessionCookie = lucia.createSessionCookie(session.id); + (await cookies()).set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes); + } + if (!session) { + const sessionCookie = lucia.createBlankSessionCookie(); + (await cookies()).set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes); + } + } catch { + // Next.js throws error attempting to set cookies when rendering page + } + return { + user, + session, + }; +}); + +declare module 'lucia' { + interface Register { + Lucia: typeof lucia; + DatabaseUserAttributes: DatabaseUserAttributes; + } } interface DatabaseUserAttributes { - username: string; -} \ No newline at end of file + username: string; + likedPosts: string[]; +} diff --git a/src/lib/hashImage.ts b/src/lib/hashImage.ts index 4563599..86cc53c 100644 --- a/src/lib/hashImage.ts +++ b/src/lib/hashImage.ts @@ -1,5 +1,4 @@ import sharp from 'sharp'; -import crypto from 'crypto'; export default async function hashImage(imageBuffer: Buffer) { try { diff --git a/src/lib/other/actions.ts b/src/lib/other/actions.ts new file mode 100644 index 0000000..43f72bd --- /dev/null +++ b/src/lib/other/actions.ts @@ -0,0 +1,50 @@ +'use server' + +import { validateRequest } from "../auth" +import prisma from "../db"; + +export async function likePost(id: string) { + const { user } = await validateRequest(); + if (!user) { + return { + success: false, + error: 'logIn', + } + } + + const post = await prisma.post.findUnique({ where: { id } }); + if (!post) { + return { + success: false, + error: 'notFound', + } + } + const userDb = await prisma.user.findUnique({ where: { id: user.id } }); + if (userDb?.likedPosts.includes(id)) { + await prisma.user.update({ + where: { id: user.id }, + data: { + likedPosts: { + set: userDb.likedPosts.filter((postId) => postId !== id), + }, + }, + }); + return { + success: true, + liked: false, + } + } + + await prisma.user.update({ + where: { id: user.id }, + data: { + likedPosts: { + push: id, + }, + }, + }); + return { + success: true, + liked: true, + } +} \ No newline at end of file