From 889548b3ba55c1b35caffe980fe7b0b3b20ee156 Mon Sep 17 00:00:00 2001 From: bombies Date: Tue, 24 Oct 2023 23:07:22 -0500 Subject: [PATCH] Implement authentication flow --- package-lock.json | 61 ++++++++++++ package.json | 1 + .../migration.sql | 11 +++ .../20231025033601_init/migration.sql | 17 ++++ .../20231025034840_init/migration.sql | 94 +++++++++++++++++++ .../migration.sql | 2 + prisma/schema.prisma | 64 +++++++------ src/app/(site)/components/NavBar.tsx | 5 +- src/app/(site)/components/UserProfile.tsx | 47 ++++++++++ .../signin/components/GoogleAuthButton.tsx | 10 +- .../signin/{ => components}/LogInForm.tsx | 2 +- src/app/(site)/signin/page.tsx | 8 +- src/app/api/auth/[...nextauth]/utils.ts | 77 ++++++++++----- src/app/api/auth/register/register.service.ts | 8 +- src/libs/types.d.ts | 7 ++ 15 files changed, 350 insertions(+), 64 deletions(-) create mode 100644 prisma/migrations/20231025033018_update_next_auth_tables/migration.sql create mode 100644 prisma/migrations/20231025033601_init/migration.sql create mode 100644 prisma/migrations/20231025034840_init/migration.sql create mode 100644 prisma/migrations/20231025035206_next_auth_update/migration.sql create mode 100644 src/app/(site)/components/UserProfile.tsx rename src/app/(site)/signin/{ => components}/LogInForm.tsx (98%) create mode 100644 src/libs/types.d.ts diff --git a/package-lock.json b/package-lock.json index 167bc4d..a0511f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "dream-logger-website", "version": "0.1.0", "dependencies": { + "@auth/prisma-adapter": "^1.0.5", "@nextui-org/react": "^2.1.13", "@prisma/client": "^5.5.0", "@theinternetfolks/snowflake": "^1.3.0", @@ -62,6 +63,58 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@auth/core": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.18.0.tgz", + "integrity": "sha512-Xb41H3FIv4PlTZmwoFvntaNlVTwIqFxIg7i0/ieHOOxf/7H8EJpGTWoNrqKhwMyZEPU6fHp+VcUiqdX3vFrWSg==", + "dependencies": { + "@panva/hkdf": "^1.0.4", + "cookie": "0.5.0", + "jose": "^4.11.1", + "oauth4webapi": "^2.0.6", + "preact": "10.11.3", + "preact-render-to-string": "5.2.3" + }, + "peerDependencies": { + "nodemailer": "^6.8.0" + }, + "peerDependenciesMeta": { + "nodemailer": { + "optional": true + } + } + }, + "node_modules/@auth/core/node_modules/preact": { + "version": "10.11.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz", + "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@auth/core/node_modules/preact-render-to-string": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz", + "integrity": "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, + "node_modules/@auth/prisma-adapter": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-1.0.5.tgz", + "integrity": "sha512-GaacU0TErURwUn/1b29LvybxUjlBxi/wIw/4imMNM+e2AfRLpB3PgpPqITQFd2PEdLTXIaHhVZvnzT4pMu9Ueg==", + "dependencies": { + "@auth/core": "0.18.0" + }, + "peerDependencies": { + "@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5" + } + }, "node_modules/@babel/runtime": { "version": "7.23.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", @@ -5701,6 +5754,14 @@ "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" }, + "node_modules/oauth4webapi": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.3.0.tgz", + "integrity": "sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", diff --git a/package.json b/package.json index 2543d4f..997d173 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@auth/prisma-adapter": "^1.0.5", "@nextui-org/react": "^2.1.13", "@prisma/client": "^5.5.0", "@theinternetfolks/snowflake": "^1.3.0", diff --git a/prisma/migrations/20231025033018_update_next_auth_tables/migration.sql b/prisma/migrations/20231025033018_update_next_auth_tables/migration.sql new file mode 100644 index 0000000..fc9a18c --- /dev/null +++ b/prisma/migrations/20231025033018_update_next_auth_tables/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - You are about to drop the column `userId` on the `Account` table. All the data in the column will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "Account" DROP CONSTRAINT "Account_userId_fkey"; + +-- AlterTable +ALTER TABLE "Account" DROP COLUMN "userId"; diff --git a/prisma/migrations/20231025033601_init/migration.sql b/prisma/migrations/20231025033601_init/migration.sql new file mode 100644 index 0000000..df65496 --- /dev/null +++ b/prisma/migrations/20231025033601_init/migration.sql @@ -0,0 +1,17 @@ +/* + Warnings: + + - You are about to drop the column `avatar` on the `User` table. All the data in the column will be lost. + - Added the required column `userId` to the `Account` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Account" ADD COLUMN "userId" TEXT NOT NULL; + +-- AlterTable +ALTER TABLE "User" DROP COLUMN "avatar", +ADD COLUMN "image" TEXT, +ADD COLUMN "name" TEXT; + +-- AddForeignKey +ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20231025034840_init/migration.sql b/prisma/migrations/20231025034840_init/migration.sql new file mode 100644 index 0000000..14bb63e --- /dev/null +++ b/prisma/migrations/20231025034840_init/migration.sql @@ -0,0 +1,94 @@ +/* + Warnings: + + - You are about to drop the column `accountProvider` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `createdAt` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `firstName` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `lastName` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `password` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `updatedAt` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `username` on the `User` table. All the data in the column will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "Dream" DROP CONSTRAINT "Dream_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "DreamCharacter" DROP CONSTRAINT "DreamCharacter_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "DreamTag" DROP CONSTRAINT "DreamTag_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "FriendRequest" DROP CONSTRAINT "FriendRequest_reveiverId_fkey"; + +-- DropForeignKey +ALTER TABLE "FriendRequest" DROP CONSTRAINT "FriendRequest_senderId_fkey"; + +-- DropForeignKey +ALTER TABLE "UserProfile" DROP CONSTRAINT "UserProfile_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "_UserFriends" DROP CONSTRAINT "_UserFriends_A_fkey"; + +-- DropForeignKey +ALTER TABLE "_UserFriends" DROP CONSTRAINT "_UserFriends_B_fkey"; + +-- DropIndex +DROP INDEX "User_username_key"; + +-- AlterTable +ALTER TABLE "User" DROP COLUMN "accountProvider", +DROP COLUMN "createdAt", +DROP COLUMN "firstName", +DROP COLUMN "lastName", +DROP COLUMN "password", +DROP COLUMN "updatedAt", +DROP COLUMN "username"; + +-- CreateTable +CREATE TABLE "Member" ( + "id" TEXT NOT NULL, + "name" TEXT, + "email" TEXT NOT NULL, + "password" TEXT, + "image" TEXT, + "accountProvider" "AccountProvider", + "username" TEXT NOT NULL, + "firstName" TEXT NOT NULL, + "lastName" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Member_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Member_email_key" ON "Member"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "Member_username_key" ON "Member"("username"); + +-- AddForeignKey +ALTER TABLE "FriendRequest" ADD CONSTRAINT "FriendRequest_senderId_fkey" FOREIGN KEY ("senderId") REFERENCES "Member"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FriendRequest" ADD CONSTRAINT "FriendRequest_reveiverId_fkey" FOREIGN KEY ("reveiverId") REFERENCES "Member"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserProfile" ADD CONSTRAINT "UserProfile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Member"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Dream" ADD CONSTRAINT "Dream_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Member"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DreamTag" ADD CONSTRAINT "DreamTag_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Member"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DreamCharacter" ADD CONSTRAINT "DreamCharacter_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Member"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserFriends" ADD CONSTRAINT "_UserFriends_A_fkey" FOREIGN KEY ("A") REFERENCES "Member"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserFriends" ADD CONSTRAINT "_UserFriends_B_fkey" FOREIGN KEY ("B") REFERENCES "Member"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20231025035206_next_auth_update/migration.sql b/prisma/migrations/20231025035206_next_auth_update/migration.sql new file mode 100644 index 0000000..7e787e5 --- /dev/null +++ b/prisma/migrations/20231025035206_next_auth_update/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "role" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fe01135..3b9e004 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -37,33 +37,32 @@ model Session { user User @relation(fields: [userId], references: [id], onDelete: Cascade) } -model VerificationToken { - identifier String - token String @unique - expires DateTime - - @@unique([identifier, token]) -} - enum AccountProvider { GOOGLE } model User { - id String @id @default(cuid()) + id String @id @default(cuid()) + name String? + role String? + email String @unique + emailVerified DateTime? + image String? + accounts Account[] + sessions Session[] +} + +model Member { + id String @id @default(cuid()) + name String? + email String @unique + password String? + image String? + + accountProvider AccountProvider? username String @unique firstName String lastName String - email String @unique - emailVerified DateTime? - password String? - avatar String? - accountProvider AccountProvider? - accounts Account[] - sessions Session[] - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt dreams Dream[] dreamTags DreamTag[] @@ -71,21 +70,32 @@ model User { UserProfile UserProfile? - friends User[] @relation("UserFriends") + friends Member[] @relation("UserFriends") // This fields only exists to satisfy prisma's relationship requiremnts. - friendsOf User[] @relation("UserFriends") + friendsOf Member[] @relation("UserFriends") sentFriendRequests FriendRequest[] @relation(name: "SentFriendRequests") friendRequests FriendRequest[] @relation(name: "ReceivedFriendRequests") + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model VerificationToken { + identifier String + token String @unique + expires DateTime + + @@unique([identifier, token]) } model FriendRequest { id String @id @default(cuid()) senderId String - sender User @relation(name: "SentFriendRequests", fields: [senderId], references: [id]) + sender Member @relation(name: "SentFriendRequests", fields: [senderId], references: [id]) reveiverId String - receiver User @relation(name: "ReceivedFriendRequests", fields: [reveiverId], references: [id]) + receiver Member @relation(name: "ReceivedFriendRequests", fields: [reveiverId], references: [id]) createdAt DateTime @default(now()) } @@ -95,7 +105,7 @@ model UserProfile { bio String? userId String @unique - user User @relation(fields: [userId], references: [id]) + user Member @relation(fields: [userId], references: [id]) } model Dream { @@ -106,7 +116,7 @@ model Dream { tags DreamTag[] characters DreamCharacter[] - user User @relation(fields: [userId], references: [id], onDelete: Cascade) + user Member @relation(fields: [userId], references: [id], onDelete: Cascade) userId String } @@ -116,7 +126,7 @@ model DreamTag { dreams Dream[] userId String - user User @relation(fields: [userId], references: [id], onDelete: Cascade) + user Member @relation(fields: [userId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -128,7 +138,7 @@ model DreamCharacter { dreams Dream[] userId String - user User @relation(fields: [userId], references: [id], onDelete: Cascade) + user Member @relation(fields: [userId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt diff --git a/src/app/(site)/components/NavBar.tsx b/src/app/(site)/components/NavBar.tsx index aaa996e..f001f26 100644 --- a/src/app/(site)/components/NavBar.tsx +++ b/src/app/(site)/components/NavBar.tsx @@ -16,11 +16,12 @@ import Button from "@/app/(site)/components/Button"; import clsx from "clsx"; import Image from "@/app/(site)/components/Image"; import {signIn, useSession} from "next-auth/react"; +import UserProfile from "@/app/(site)/components/UserProfile"; const NavBar: FC = () => { const [isMenuOpen, setMenuOpen] = useState(false) const pathName = usePathname(); - const {status: authStatus} = useSession() + const {data: session, status: authStatus} = useSession() return ( { : ( - {/*TODO: Set up user profile*/} + ) } diff --git a/src/app/(site)/components/UserProfile.tsx b/src/app/(site)/components/UserProfile.tsx new file mode 100644 index 0000000..c106cf8 --- /dev/null +++ b/src/app/(site)/components/UserProfile.tsx @@ -0,0 +1,47 @@ +import {FC} from "react"; +import {Avatar, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger} from "@nextui-org/react"; +import {Divider} from "@nextui-org/divider"; +import {signOut} from "next-auth/react"; + +type Props = { + user: any +} + +const UserProfile: FC = ({user}) => { + console.log(user) + + return ( + + + + + { + switch (key) { + case "log_out": { + signOut() + break; + } + } + }} + > + +

Hey {user.firstName}

+ +
+ + Sign Out + +
+
+ ) +} + +export default UserProfile \ No newline at end of file diff --git a/src/app/(site)/signin/components/GoogleAuthButton.tsx b/src/app/(site)/signin/components/GoogleAuthButton.tsx index 0588bee..0d268bc 100644 --- a/src/app/(site)/signin/components/GoogleAuthButton.tsx +++ b/src/app/(site)/signin/components/GoogleAuthButton.tsx @@ -1,20 +1,28 @@ +"use client" + import {FC} from "react"; import Button from "@/app/(site)/components/Button"; import GoogleIcon from "@/app/(site)/components/icons/GoogleIcon"; import {signIn} from "next-auth/react"; +import {useRouter} from "next/navigation"; +import toast from "react-hot-toast"; type Props = { type: 'signin' | 'signup' } const GoogleAuthButton: FC = ({type}) => { + const router = useRouter() + return (