diff --git a/app/(Main)/[username]/page.tsx b/app/(Main)/[username]/page.tsx index fd7d8ec1..3a41c294 100644 --- a/app/(Main)/[username]/page.tsx +++ b/app/(Main)/[username]/page.tsx @@ -14,11 +14,23 @@ export default async function Page({ params }: { username: string } }) { - const rows = await postgres.user.findMany({ + const user = await postgres.user.findFirst({ include: { - posts: true, - Followers: true, - Following: true + posts: { + orderBy: { + createdAt: "desc" + }, + }, + Followers: { + include: { + following: true + } + }, + Followings: { + include: { + follower: true + } + } }, where: { username: params.username @@ -28,7 +40,6 @@ export default async function Page({ params }: { const session = await getServerSession(); console.log(session); - const user = rows[0]; if (!user) redirect("/404"); const posts = user.posts; @@ -54,56 +65,10 @@ export default async function Page({ params }: { const sessionUserName = await getSession(); console.log(sessionUserName); - // const [user, setUser] = useState(null); // Replace 'any' with the actual type of your user data - // const [isLoaded, setIsLoaded] = useState(false); - // const { status, data: session } = useSession(); - // - // - // const [sessionUser, setSessionUser] = useState(null); - // const [deleted, setDeleted] = useState(false); - // const [posts, setPosts] = useState(null); - // const router = useRouter(); - // useEffect(() => { - // async function fetchData() { - // try { - // const userData = await getUserByUsername(params.username); - // setPosts(userData.posts); - // } catch (error) { - // console.error(error); - // } - // } - - // fetchData(); - // }, [deleted]); - - // async function handleDelete(posturl: string) { - // await fetch(`/api/posts/${user?.username}?postid=${posturl}`, { - // method: "DELETE", - // }); - // setDeleted(true); - // } - - - // if (!isLoaded) { - // // Loading skeleton or spinner while fetching data - // return ( - //
- // - //
- // ) - // } - - - - return (
- +
); diff --git a/app/(Main)/feed/page.tsx b/app/(Main)/feed/page.tsx index 9327afda..d7238860 100644 --- a/app/(Main)/feed/page.tsx +++ b/app/(Main)/feed/page.tsx @@ -23,7 +23,7 @@ export default function Feed() { useEffect(() => { async function fetchFeed() { if (status !== "unauthenticated") { - const user = (await sessionUser).id + const user = (await sessionUser)?.id try { const response = await fetch(`/api/feed?user=${user}&page=${page}`); if (!response.ok) { diff --git a/app/(Main)/layout.tsx b/app/(Main)/layout.tsx index 19b966a5..9726dac9 100644 --- a/app/(Main)/layout.tsx +++ b/app/(Main)/layout.tsx @@ -14,7 +14,7 @@ export default function MainLayout({ return ( <> { - status === 'authenticated' ? : + status != 'authenticated' ? : }
diff --git a/app/(Main)/tag/[tagname]/page.tsx b/app/(Main)/tag/[tagname]/page.tsx index a73c5b37..87a63fd0 100644 --- a/app/(Main)/tag/[tagname]/page.tsx +++ b/app/(Main)/tag/[tagname]/page.tsx @@ -5,7 +5,7 @@ import TagDetails from "@/components/tags/details"; import FollowTagButton from "@/components/tags/follow-btn"; import TagPosts from "@/components/tags/post"; import postgres from "@/lib/postgres"; -import { getSession } from "next-auth/react"; +import { getSession, } from "next-auth/react"; import { redirect } from "next/navigation"; @@ -17,6 +17,7 @@ export default async function TagPage({ params }: { params: { tagname: string } }, include: { followingtag: true, + _count: { select: { posts: true, followingtag: true } } }, orderBy: { posts: { diff --git a/app/api/feed/route.ts b/app/api/feed/route.ts index 89378de8..eacf9e68 100644 --- a/app/api/feed/route.ts +++ b/app/api/feed/route.ts @@ -3,8 +3,8 @@ import { NextRequest, NextResponse } from 'next/server' export async function GET(req: NextRequest, res: NextResponse) { try { - const user_id = req.nextUrl.searchParams.get('user') as string - let page = parseInt(req.nextUrl.searchParams.get('page') || '0', 10) + const user_id = Number(req.nextUrl.searchParams.get('user')) + let page = parseInt(req.nextUrl.searchParams.get('page')!) let limit = 10 let offset = 0 @@ -13,18 +13,6 @@ export async function GET(req: NextRequest, res: NextResponse) { offset = (page + 1) * limit } - // const feed = await sql` - // SELECT * - // FROM BlogPosts - // WHERE authorid IN ( - // SELECT followeeid - // FROM Follows - // WHERE followerid = ${user_id} - // ) - // ORDER BY creationdate DESC - // LIMIT ${limit} OFFSET ${offset} - // ` - // const feed = await sql('SELECT * FROM BlogPosts WHERE authorid IN (SELECT followeeid FROM Follows WHERE followerid = $1) ORDER BY creationdate DESC LIMIT $2 OFFSET $3', [user_id, limit, offset]) const userFollowings = await postgres.follow.findMany({ select: { followingId: true, @@ -56,17 +44,9 @@ export async function GET(req: NextRequest, res: NextResponse) { tags: true, } }) - //execute algorithm to determine the end of the feed - // const feedLength = await sql` - // SELECT COUNT(*) AS feedlength - // FROM BlogPosts - // WHERE authorid IN ( - // SELECT followeeid - // FROM Follows - // WHERE followerid = ${user_id} - // ) - // `; - const feedLength = postgres.post.count({ + + // check if there are more posts + const feedLength = await postgres.post.count({ where: { authorId: { in: userFollowings.map((user) => user.followingId), @@ -74,28 +54,6 @@ export async function GET(req: NextRequest, res: NextResponse) { }, }) - //execute a query to fetch the number of comments of the posts - // const postComments = await sql` - // SELECT blogpostid, COUNT(*) AS commentscount - // FROM Comments - // GROUP BY blogpostid - // `; - - // const author = await sql` - // SELECT * - // FROM Users - // WHERE userid IN ( - // SELECT authorid - // FROM BlogPosts - // WHERE authorid IN ( - // SELECT followeeid - // FROM Follows - // WHERE followerid = ${user_id} - // ) - // ) - // ` - - const popular = await postgres.post.findMany({ orderBy: { views: 'desc', diff --git a/app/api/follow/route.ts b/app/api/follow/route.ts index b145d756..a1b47f3a 100644 --- a/app/api/follow/route.ts +++ b/app/api/follow/route.ts @@ -3,8 +3,8 @@ import postgres from "@/lib/postgres"; export async function GET(request: NextRequest) { try{ - const followeeId = request.nextUrl.searchParams.get("followeeId"); - const followerId = request.nextUrl.searchParams.get("followerId"); + const followeeId = Number(request.nextUrl.searchParams.get("followeeId")); + const followerId = Number(request.nextUrl.searchParams.get("followerId")); if (!followeeId || !followerId) { return new Response("followeeId and followerId are required query parameters", { status: 400 }); diff --git a/app/api/follow/tag/route.ts b/app/api/follow/tag/route.ts index 2a522f03..ad24301a 100644 --- a/app/api/follow/tag/route.ts +++ b/app/api/follow/tag/route.ts @@ -1,9 +1,9 @@ import postgres from "@/lib/postgres" import { NextRequest, NextResponse } from "next/server"; -export async function POST(request: NextRequest){ +export async function GET(request: NextRequest){ const tagid = Number(request.nextUrl.searchParams.get("tagId")) - const userid = request.nextUrl.searchParams.get("userId") + const userid = Number(request.nextUrl.searchParams.get("userId")) try { if (!tagid || !userid){ diff --git a/app/api/posts/validate-url/route.ts b/app/api/posts/validate-url/route.ts index 87c33151..5b4f3cec 100644 --- a/app/api/posts/validate-url/route.ts +++ b/app/api/posts/validate-url/route.ts @@ -4,7 +4,7 @@ import postgres from "@/lib/postgres"; export async function GET(request: NextRequest) { try { const url = request.nextUrl.searchParams.get("url"); - const authorId = request.nextUrl.searchParams.get("authorId")?.toString(); + const authorId = Number(request.nextUrl.searchParams.get("author")); if (!url) { return new Response("url is required query parameter", { status: 400 }); diff --git a/app/api/revalidate/route.ts b/app/api/revalidate/route.ts new file mode 100644 index 00000000..b44561b2 --- /dev/null +++ b/app/api/revalidate/route.ts @@ -0,0 +1,17 @@ +import { revalidatePath } from 'next/cache' +import { NextRequest } from 'next/server' + +export async function GET(request: NextRequest) { + const path = request.nextUrl.searchParams.get('path') + + if (path) { + revalidatePath(path) + return Response.json({ revalidated: true, now: Date.now() }) + } + + return Response.json({ + revalidated: false, + now: Date.now(), + message: 'Missing path to revalidate', + }) +} \ No newline at end of file diff --git a/app/api/users/[username]/route.ts b/app/api/users/[username]/route.ts index 35118bc5..edc936a6 100644 --- a/app/api/users/[username]/route.ts +++ b/app/api/users/[username]/route.ts @@ -3,7 +3,6 @@ import { NextResponse } from 'next/server'; export async function GET(req: Request, { params }: { params: { username: string }}) { try { - // Get the 'slug' route parameter from the request object const username = params.username; if (username === undefined || username === null) { @@ -14,8 +13,16 @@ export async function GET(req: Request, { params }: { params: { username: string const result = await postgres.user.findFirst({ include: { posts: true, - Followers: true, - Following: true, + Followers: { + include: { + following: true + } + }, + Following: { + include: { + follower: true + } + }, notifications: true, }, where: { @@ -23,13 +30,6 @@ export async function GET(req: Request, { params }: { params: { username: string } }) - const posts = await postgres.post.findMany({ - where: { - authorId: result?.id, - visibility: "public", - } - }) - if (!result) { return NextResponse.json({ error: 'User not found' }, { status: 404 }); } diff --git a/app/api/users/route.ts b/app/api/users/route.ts index 8a4610c7..f83f23ea 100644 --- a/app/api/users/route.ts +++ b/app/api/users/route.ts @@ -3,7 +3,7 @@ import { NextRequest, NextResponse } from 'next/server'; export async function GET(request: NextRequest) { try { - const id = request.nextUrl.searchParams.get("id"); + const id = Number(request.nextUrl.searchParams.get("id")); if (id) { const user = await postgres.user.findUnique({ where: { @@ -13,8 +13,8 @@ export async function GET(request: NextRequest) { return NextResponse.json({ user: user }, { status: 200}); } else { const result = await postgres.user.findMany() - - const user = result; + const user = result; + return NextResponse.json({ user }, { status: 200}); } // Execute a query to fetch all table name diff --git a/app/api/users/top/route.ts b/app/api/users/top/route.ts index de71cf41..a95ebdc0 100644 --- a/app/api/users/top/route.ts +++ b/app/api/users/top/route.ts @@ -4,7 +4,7 @@ import { NextRequest, NextResponse } from "next/server"; // api to execute the top users query by followers and return the result export async function GET(request: NextRequest) { try { - const userid = request.nextUrl.searchParams.get("user")?.toString(); + const userid = Number(request.nextUrl.searchParams.get("user")); // execute the query to fetch the top 5 users by followers where the user is not following them and dont display the user itself @@ -20,6 +20,15 @@ export async function GET(request: NextRequest) { // LIMIT 5 // `; // const users = await sql('SELECT * FROM Users WHERE userid NOT IN (SELECT followeeid FROM Follows WHERE followerid = $1) AND userid <> $1 ORDER BY (SELECT COUNT(*) FROM Follows WHERE followeeid = Users.userid) DESC LIMIT 5', [userid]) + const userFollowings = await postgres.follow.findMany({ + select: { + followingId: true, + }, + where: { + followerId: userid, + }, + }); + const topUsers = await postgres.user.findMany({ include: { Followers: true, @@ -28,15 +37,13 @@ export async function GET(request: NextRequest) { }, take: 5, where: { - Followers: { - some: { - followerId: { - not: userid, // Replace with the user's ID - }, // Replace with the user's ID - }, - }, id: { - not: userid, // Replace with the user's ID + not: userid, + }, + Following: { + none: { + followerId: userid, + }, }, }, orderBy: { diff --git a/app/auth.ts b/app/auth.ts index 849d2fec..3890a951 100644 --- a/app/auth.ts +++ b/app/auth.ts @@ -39,13 +39,13 @@ export const config = { await postgres.user.create({ data: { username: username, - name: name || '', - email: email || '', - bio: bio || '', + name: name, + email: email, + bio: bio, githubprofile: githubProfileURL, - location: location || '', + location: location, image: avatar_url, - password: '' + password: "github" } }) diff --git a/components/feed/featured/featured-dev.tsx b/components/feed/featured/featured-dev.tsx index 2253db4a..d2affa50 100644 --- a/components/feed/featured/featured-dev.tsx +++ b/components/feed/featured/featured-dev.tsx @@ -52,7 +52,7 @@ export default function FeaturedDev( setIsFollowingLoading(newLoadingStates); try { - const followerId = (await getSessionUser()).id; + const followerId = (await getSessionUser())?.id; await fetch(`/api/follow?followeeId=${followeeId}&followerId=${followerId}`, { method: "GET", diff --git a/components/navbar/user-nav.tsx b/components/navbar/user-nav.tsx index 1e8b163b..90015204 100644 --- a/components/navbar/user-nav.tsx +++ b/components/navbar/user-nav.tsx @@ -20,29 +20,29 @@ import { signOut, useSession } from "next-auth/react" import Link from "next/link" import { useEffect, useState } from "react" import { getUserByUsername } from "../get-user" +import { getSessionUser } from "../get-session-user" export function UserNav() { - const [isLoading, setLoading] = useState(true) const { status } = useSession(); const user = useSession().data?.user as any; - const [username, setUsername] = useState(null); + const [username, setUsername] = useState(null); - useEffect(() => { - async function fetchData() { - try { - const userData = await getUserByUsername(user?.name); - setUsername(userData.username); - } catch (error) { - // Handle errors - console.error('Error:', error); - } - } +useEffect(() => { + async function fetchData() { + try { + const userData = (await getSessionUser())?.username; + setUsername(userData ?? null); + } catch (error) { + // Handle errors + console.error('Error:', error); + } + } - if (status === "authenticated") { + if (status === "authenticated") { fetchData(); - setLoading(false); } - }, [status, user?.name]); +}, [status, user?.name]); + return ( diff --git a/components/tags/details.tsx b/components/tags/details.tsx index 41b794e9..851a8377 100644 --- a/components/tags/details.tsx +++ b/components/tags/details.tsx @@ -7,11 +7,14 @@ import { useSession } from "next-auth/react"; import LoginDialog from "../login-dialog"; import { is } from "date-fns/locale"; import { revalidatePath } from "next/cache"; +import { useRouter } from "next/navigation"; +import { set } from "date-fns"; export default function TagDetails({ tag, post, tagFollowers }: { tag: any, post: any, tagFollowers: any }) { const session = async () => { return await getSessionUser(); }; + const router = useRouter(); const { status: sessionStatus } = useSession(); @@ -19,38 +22,43 @@ export default function TagDetails({ tag, post, tagFollowers }: { tag: any, post const [isFollowingLoading, setIsFollowingLoading] = useState(false); const user = session() as any; - useEffect(() => { - if (user) { - tagFollowers.forEach((follower: any) => { - if (follower.userid === user.id) { - setIsFollowing(true); - } - }) + async function fetchData() { + if (sessionStatus !== "unauthenticated") { + try { + const userid = (await getSessionUser())?.id; + setIsFollowing(tagFollowers.find((user: any) => user.followerId === userid)) + } catch (error) { + console.error(error); + } } - }, [user]); + } + + useEffect(() => { + fetchData(); + }, [sessionStatus]); const handleFollow = () => async () => { if (sessionStatus === "authenticated") { setIsFollowingLoading(true); try { setIsFollowing(!isFollowing); - const userid = (await session()).id; + const userid = (await getSessionUser())?.id; const response = await fetch(`/api/follow/tag?tagId=${tag.id}&userId=${userid}`, { - method: "POST", + method: "GET", }); if (!response.ok) { setIsFollowing(!isFollowing); } - setIsFollowingLoading(false); } catch (error) { console.error(error); setIsFollowingLoading(false); } - revalidatePath(`/tag/${tag.name}`); - } else { - return null; - }; + await fetch(`/api/revalidate?path=/tag/${tag.id}`, { + method: "GET", + }); + router.refresh(); + } } @@ -59,7 +67,7 @@ export default function TagDetails({ tag, post, tagFollowers }: { tag: any, post

{tag.name}

- Tag
·
{formatNumberWithSuffix(post)} Posts
·
{formatNumberWithSuffix(tagFollowers.length)} Followers + Tag
·
{formatNumberWithSuffix(post.length)} Posts
·
{formatNumberWithSuffix(tagFollowers.length)} Followers
{ diff --git a/components/user/details.tsx b/components/user/details.tsx index f61b1b4b..6350131e 100644 --- a/components/user/details.tsx +++ b/components/user/details.tsx @@ -15,277 +15,287 @@ import { useState, useEffect } from "react"; import { getSessionUser } from "../get-session-user"; import { useRef } from "react"; +import { revalidatePath } from "next/cache"; +import { useRouter } from "next/navigation"; +import { is, ro } from "date-fns/locale"; +import { set } from "date-fns"; function getRegistrationDateDisplay(registrationDate: string) { - ///format date ex: if published this year Apr 4, otherwise Apr 4, 2021 - const date = new Date(registrationDate) - const currentYear = new Date().getFullYear() - const year = date.getFullYear() - const formattedDate = date.toLocaleDateString("en-US", { - month: "short", - day: "numeric", - hour12: true, - }) - if (year !== currentYear) { - return date.toLocaleDateString("en-US", { - year: "numeric", - month: "short", - day: "numeric", - hour12: true, - }) - } - return formattedDate - } + ///format date ex: if published this year Apr 4, otherwise Apr 4, 2021 + const date = new Date(registrationDate) + const currentYear = new Date().getFullYear() + const year = date.getFullYear() + const formattedDate = date.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + hour12: true, + }) + if (year !== currentYear) { + return date.toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + hour12: true, + }) + } + return formattedDate +} -export default function UserDetails({ className, children, user, followers, followings} : { children?: React.ReactNode, className?: string, user : any, followers: any, followings: any }) { - const { data: session, status } = useSession(); - const [isFollowing, setIsFollowing] = useState(null); - const [isFollowingLoading, setIsFollowingLoading] = useState(false); - const followersRef = useRef(followers); - - useEffect(() => { - async function fetchData(followersRef: React.MutableRefObject, user: any, status: string) { - if (status === "authenticated") { - const followerId = (await getSessionUser()).id; - const userFollowers = await fetch(`/api/users/${user?.username}`); - const followers = await userFollowers.json().then((res) => res.user.followers); - followersRef.current = followers; - setIsFollowing(followers.find((follower: any) => follower.followerId === followerId)); - } +export default function UserDetails({ className, children, user, followers, followings }: { children?: React.ReactNode, className?: string, user: any, followers: any, followings: any }) { + const { data: session, status } = useSession(); + const [isFollowing, setIsFollowing] = useState(null); + const [isFollowingLoading, setIsFollowingLoading] = useState(false); + const router = useRouter(); + const [isLoaded, setIsLoaded] = useState(false); + + async function fetchData() { + if (status !== "unauthenticated") { + try { + const followerId = (await getSessionUser())?.id; + setIsFollowing(followers.find((follower: any) => follower.followerId === followerId)); + } catch (error) { + console.error(error); } + } + } - - fetchData(followersRef, user, status); - }, [isFollowing]); + useEffect(() => { + fetchData(); + setIsLoaded(true); + }, [status]); - async function handleFollow(followeeId: string) { + async function handleFollow(followeeId: string) { if (status === "authenticated") { setIsFollowingLoading(true); - try { - setIsFollowing(!isFollowing); - const followerId = (await getSessionUser()).id; - const result = await fetch(`/api/follow?followeeId=${followeeId}&followerId=${followerId}`, { - method: "GET", - }); - if (!result.ok) { + try { setIsFollowing(!isFollowing); - } - setIsFollowingLoading(false); + const followerId = (await getSessionUser())?.id; + const result = await fetch(`/api/follow?followeeId=${followeeId}&followerId=${followerId}`, { + method: "GET", + }); + if (!result.ok) { + setIsFollowing(!isFollowing); + } + setIsFollowingLoading(false); } catch (error) { console.error(error); setIsFollowingLoading(false); } - } else { - return null; + await fetch(`api/revalidate?path=/${user?.username}`, { + method: 'GET' + }) + router.refresh(); } - } - - return ( -
-
- - - {user?.name === null ? user?.username?.charAt(0) : user?.name?.charAt(0)} - -
- { - user?.name === null ? ( -

- {user?.username} {user?.verified && ( - - - - )} { user?.falsemember && ( - - ) } -

- ) : ( -

- {user?.name} {user?.verified && ( - - - - )} { user?.falsemember && ( - - ) } - {user?.username} -

) - } -
-
- { - status === "authenticated"? ( - session?.user?.name === user?.name || session?.user?.name === user?.username ? ( - - ) : ( - - ) - ) : ( - - - - ) - } - - {user?.bio && (
{user?.bio}
)} + } -
- - - - - - Followers - -
- {followersRef.current.map((follower: any) => ( -
-
- - - - - {follower.name?.charAt(0) || follower.username?.charAt(0)} - - { - follower.name === null ? ( -
-

{follower.username} {follower?.verified && ( - - - - )}

-
- ) : ( -
-

{follower.name} {follower?.verified && ( - - - - )}

-

{follower.username}

-
- ) - } - -
-
- -
- )) - } - { - followersRef.current.length === 0 && ( -

No followers

- ) - } -
-
-
- - - - - Followings - -
- {followings.map((following: any) => ( -
-
- - - - - {following.name?.charAt(0) || following.username?.charAt(0)} - + return ( + isLoaded && ( +
+
+ + + {user?.name === null ? user?.username?.charAt(0) : user?.name?.charAt(0)} + +
{ - following.name === null ? ( -
-

{following.username} {following?.verified && ( - - - - )}

-
+ user?.name === null ? ( +

+ {user?.username} {user?.verified && ( + + + + )} {user?.falsemember && ( + + )} +

) : ( -
-

{following.name} {following?.verified && ( - - - - )}

-

{following.username}

-
- ) +

+ {user?.name} {user?.verified && ( + + + + )} {user?.falsemember && ( + + )} + {user?.username} +

) } - -
-
- )) - } { - followings.length === 0 && ( -

No followings

+ status === "authenticated" ? ( + session?.user?.name === user?.name || session?.user?.name === user?.username ? ( + + ) : ( + + ) + ) : ( + + + ) } -
- -
-
+ {user.bio !== '' && (
{user?.bio}
)} -
    - {user?.location &&
  • - -
  • } - {user?.email &&
  • - -
  • } -
  • - -
  • -
  • - -
  • -
-
- ) +
+ + + + + + Followers + +
+ {followers.map((follower: any) => ( +
+
+ + + + + {follower.follower?.name?.charAt(0) || follower.follower?.username?.charAt(0)} + + { + follower.follower?.name === null ? ( +
+

{follower.follower?.username} {follower?.follower?.verified && ( + + + + )}

+
+ ) : ( +
+

{follower.follower?.name} {follower?.follower?.verified && ( + + + + )}

+

{follower.follower?.username}

+
+ ) + } + +
+
+ +
+ )) + } + { + followers.length === 0 && ( +

No followers

+ ) + } +
+
+
+ + + + + Followings + +
+ {followings.map((following: any) => ( +
+
+ + + + + {following.following.name?.charAt(0) || following.following.username?.charAt(0)} + + { + following.following.name === null ? ( +
+

{following.following.username} {following?.following.verified && ( + + + + )}

+
+ ) : ( +
+

{following.following.name} {following?.following.verified && ( + + + + )}

+

{following.following.username}

+
+ ) + } + +
+
+ +
+ )) + } + + { + followings.length === 0 && ( +

No followings

+ ) + } +
+
+
+ +
+ +
    + {user?.location &&
  • + +
  • } + {user?.email &&
  • + +
  • } +
  • + +
  • +
  • + +
  • +
+
) + ) } \ No newline at end of file diff --git a/knexfile.js b/knexfile.js new file mode 100644 index 00000000..d835a6ea --- /dev/null +++ b/knexfile.js @@ -0,0 +1,5 @@ +const pg = require('knex')({ + client: 'pg', + connection: process.env.PG_CONNECTION_STRING, + searchPath: ['knex', 'public'], +}); \ No newline at end of file diff --git a/prisma/migrations/20231024123040_/migration.sql b/prisma/migrations/20231024123040_/migration.sql new file mode 100644 index 00000000..0e63b948 --- /dev/null +++ b/prisma/migrations/20231024123040_/migration.sql @@ -0,0 +1,145 @@ +/* + Warnings: + + - The primary key for the `users` table will be changed. If it partially fails, the table could be left without primary key constraint. + - The `id` column on the `users` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - Changed the type of `user_id` on the `accounts` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `userId` on the `bookmarks` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `authorId` on the `commentlikes` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `authorId` on the `comments` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `followerId` on the `follows` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `followingId` on the `follows` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `authorId` on the `likes` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `receiverId` on the `notifications` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `authorId` on the `posts` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `user_id` on the `sessions` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `followerId` on the `tagfollows` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + - Changed the type of `userId` on the `usersettings` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- DropForeignKey +ALTER TABLE "accounts" DROP CONSTRAINT "accounts_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "bookmarks" DROP CONSTRAINT "bookmarks_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "commentlikes" DROP CONSTRAINT "commentlikes_authorId_fkey"; + +-- DropForeignKey +ALTER TABLE "comments" DROP CONSTRAINT "comments_authorId_fkey"; + +-- DropForeignKey +ALTER TABLE "follows" DROP CONSTRAINT "follows_followerId_fkey"; + +-- DropForeignKey +ALTER TABLE "follows" DROP CONSTRAINT "follows_followingId_fkey"; + +-- DropForeignKey +ALTER TABLE "likes" DROP CONSTRAINT "likes_authorId_fkey"; + +-- DropForeignKey +ALTER TABLE "notifications" DROP CONSTRAINT "notifications_receiverId_fkey"; + +-- DropForeignKey +ALTER TABLE "posts" DROP CONSTRAINT "posts_authorId_fkey"; + +-- DropForeignKey +ALTER TABLE "sessions" DROP CONSTRAINT "sessions_user_id_fkey"; + +-- DropForeignKey +ALTER TABLE "tagfollows" DROP CONSTRAINT "tagfollows_followerId_fkey"; + +-- DropForeignKey +ALTER TABLE "usersettings" DROP CONSTRAINT "usersettings_userId_fkey"; + +-- AlterTable +ALTER TABLE "accounts" DROP COLUMN "user_id", +ADD COLUMN "user_id" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "bookmarks" DROP COLUMN "userId", +ADD COLUMN "userId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "commentlikes" DROP COLUMN "authorId", +ADD COLUMN "authorId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "comments" DROP COLUMN "authorId", +ADD COLUMN "authorId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "follows" DROP COLUMN "followerId", +ADD COLUMN "followerId" INTEGER NOT NULL, +DROP COLUMN "followingId", +ADD COLUMN "followingId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "likes" DROP COLUMN "authorId", +ADD COLUMN "authorId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "notifications" DROP COLUMN "receiverId", +ADD COLUMN "receiverId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "posts" DROP COLUMN "authorId", +ADD COLUMN "authorId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "sessions" DROP COLUMN "user_id", +ADD COLUMN "user_id" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "tagfollows" DROP COLUMN "followerId", +ADD COLUMN "followerId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "users" DROP CONSTRAINT "users_pkey", +DROP COLUMN "id", +ADD COLUMN "id" SERIAL NOT NULL, +ADD CONSTRAINT "users_pkey" PRIMARY KEY ("id"); + +-- AlterTable +ALTER TABLE "usersettings" DROP COLUMN "userId", +ADD COLUMN "userId" INTEGER NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "usersettings_userId_key" ON "usersettings"("userId"); + +-- AddForeignKey +ALTER TABLE "accounts" ADD CONSTRAINT "accounts_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "posts" ADD CONSTRAINT "posts_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comments" ADD CONSTRAINT "comments_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "likes" ADD CONSTRAINT "likes_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "commentlikes" ADD CONSTRAINT "commentlikes_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "follows" ADD CONSTRAINT "follows_followerId_fkey" FOREIGN KEY ("followerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "follows" ADD CONSTRAINT "follows_followingId_fkey" FOREIGN KEY ("followingId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "tagfollows" ADD CONSTRAINT "tagfollows_followerId_fkey" FOREIGN KEY ("followerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "notifications" ADD CONSTRAINT "notifications_receiverId_fkey" FOREIGN KEY ("receiverId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "bookmarks" ADD CONSTRAINT "bookmarks_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "usersettings" ADD CONSTRAINT "usersettings_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20231025114347_/migration.sql b/prisma/migrations/20231025114347_/migration.sql new file mode 100644 index 00000000..45004239 --- /dev/null +++ b/prisma/migrations/20231025114347_/migration.sql @@ -0,0 +1,13 @@ +/* + Warnings: + + - Made the column `username` on table `users` required. This step will fail if there are existing NULL values in that column. + +*/ +-- AlterTable +ALTER TABLE "users" ALTER COLUMN "email" DROP NOT NULL, +ALTER COLUMN "username" SET NOT NULL, +ALTER COLUMN "name" DROP NOT NULL, +ALTER COLUMN "bio" DROP NOT NULL, +ALTER COLUMN "password" DROP NOT NULL, +ALTER COLUMN "location" DROP NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6f2b8796..497270b6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,6 +11,76 @@ datasource db { } +model Account { + id String @id @default(cuid()) + userId Int @map("user_id") + type String + provider String + providerAccountId String @map("provider_account_id") + refresh_token String? @db.Text + access_token String? @db.Text + expires_at Int? + token_type String? + scope String? + id_token String? @db.Text + session_state String? + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([provider, providerAccountId]) + @@map("accounts") +} + +model Session { + id String @id @default(cuid()) + sessionToken String @unique @map("session_token") + userId Int @map("user_id") + expires DateTime + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("sessions") +} + +model VerificationToken { + identifier String + token String @unique + expires DateTime + + @@unique([identifier, token]) + @@map("verificationtokens") +} + +model User { + id Int @id @default(autoincrement()) + email String? @unique + username String @unique + name String? + bio String? + password String? + emailVerified DateTime? @map("email_verified") + image String? + accounts Account[] + sessions Session[] + githubprofile String + location String? + verified Boolean @default(false) + falsemember Boolean @default(false) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + settings UserSettings? + notifications Notification[] + posts Post[] + comments Comment[] + likes Like[] + commentlikes CommentLike[] + Followings Follow[] @relation("Follower") + Followers Follow[] @relation("Following") + tagfollower TagFollow[] @relation("TagFollower") + bookmarks Bookmark[] + + + @@map("users") +} model Post { id Int @id @default(autoincrement()) @@ -22,7 +92,7 @@ model Post { cover String views Int @default(0) author User @relation(fields: [authorId], references: [id]) - authorId String + authorId Int url String? @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -41,7 +111,7 @@ model Comment { id Int @id @default(autoincrement()) content String author User @relation(fields: [authorId], references: [id]) - authorId String + authorId Int post Post @relation(fields: [postId], references: [id]) postId Int createdAt DateTime @default(now()) @@ -55,7 +125,7 @@ model Comment { model Like { id Int @id @default(autoincrement()) author User @relation(fields: [authorId], references: [id]) - authorId String + authorId Int post Post @relation(fields: [postId], references: [id]) postId Int createdAt DateTime @default(now()) @@ -67,7 +137,7 @@ model Like { model CommentLike { id Int @id @default(autoincrement()) author User @relation(fields: [authorId], references: [id]) - authorId String + authorId Int comment Comment @relation(fields: [commentId], references: [id]) commentId Int createdAt DateTime @default(now()) @@ -102,9 +172,9 @@ model PostTag { model Follow { id Int @id @default(autoincrement()) follower User @relation("Follower", fields: [followerId], references: [id]) - followerId String + followerId Int following User @relation("Following", fields: [followingId], references: [id]) - followingId String + followingId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -114,7 +184,7 @@ model Follow { model TagFollow { id Int @id @default(autoincrement()) follower User @relation("TagFollower", fields: [followerId], references: [id]) - followerId String + followerId Int tag Tag @relation("FollowingTag", fields: [tagId], references: [id]) tagId Int createdAt DateTime @default(now()) @@ -128,7 +198,7 @@ model Notification { content String read Boolean @default(false) receiver User @relation(fields: [receiverId], references: [id]) - receiverId String + receiverId Int type String? url String senderId Int? @@ -144,7 +214,7 @@ model Bookmark { post Post @relation(fields: [postId], references: [id]) postId Int user User @relation(fields: [userId], references: [id]) - userId String + userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -154,7 +224,7 @@ model Bookmark { model UserSettings { id Int @id @default(autoincrement()) user User @relation(fields: [userId], references: [id]) - userId String @unique + userId Int @unique appearance String @default("system") language String @default("en") createdAt DateTime @default(now()) @@ -162,74 +232,3 @@ model UserSettings { @@map("usersettings") } - -model Account { - id String @id @default(cuid()) - userId String @map("user_id") - type String - provider String - providerAccountId String @map("provider_account_id") - refresh_token String? @db.Text - access_token String? @db.Text - expires_at Int? - token_type String? - scope String? - id_token String? @db.Text - session_state String? - - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - - @@unique([provider, providerAccountId]) - @@map("accounts") -} - -model Session { - id String @id @default(cuid()) - sessionToken String @unique @map("session_token") - userId String @map("user_id") - expires DateTime - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - - @@map("sessions") -} - -model VerificationToken { - identifier String - token String @unique - expires DateTime - - @@unique([identifier, token]) - @@map("verificationtokens") -} - -model User { - id String @id @default(cuid()) - email String @unique - username String? @unique - name String - bio String - password String - emailVerified DateTime? @map("email_verified") - image String? - accounts Account[] - sessions Session[] - githubprofile String - location String - verified Boolean @default(false) - falsemember Boolean @default(false) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - settings UserSettings? - notifications Notification[] - posts Post[] - comments Comment[] - likes Like[] - commentlikes CommentLike[] - Followers Follow[] @relation("Follower") - Following Follow[] @relation("Following") - tagfollower TagFollow[] @relation("TagFollower") - bookmarks Bookmark[] - - - @@map("users") -} \ No newline at end of file