Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development #47

Merged
merged 24 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
55a1129
added logout button to navbar, mobile and desktop
aasmal97 Oct 17, 2023
fe23d04
added generate dropdown links in mobile sidebar, and adpated user pro…
aasmal97 Oct 18, 2023
bd3756e
added prisma client, schemas, and sign up routes. Added sign up route…
aasmal97 Oct 19, 2023
0eae2cf
added session callback and appropiate types
aasmal97 Oct 19, 2023
5ff13e4
removed window width state value from hook
aasmal97 Oct 19, 2023
d6e44ce
changed imports to next router to next naviagation router
aasmal97 Oct 19, 2023
b09025e
Add signout button to navbar and add session hook to navbar components
aasmal97 Oct 19, 2023
609fc9f
add dynamic data to user profile component
aasmal97 Oct 19, 2023
974e73b
added provider key in body creds object from auth form. Also added st…
aasmal97 Oct 20, 2023
b808933
added prisma connection function, and added disconnect logic everytim…
aasmal97 Oct 20, 2023
b4f7656
added new prisma schemas and added create user route. Validated googl…
aasmal97 Oct 21, 2023
b44991c
add redirect logic to login and signup pages
aasmal97 Oct 21, 2023
807a1eb
removed use client from login page, which caused errors
aasmal97 Oct 21, 2023
43ddb47
adjusted sign in logic to always create a user cred file on google si…
aasmal97 Oct 21, 2023
20d4c84
added auto login when sign up is initiated
aasmal97 Oct 21, 2023
fd09299
added error message parsing and error page logic
aasmal97 Oct 21, 2023
0e9bb4e
remove unneeded console.logs
aasmal97 Oct 21, 2023
b13289e
added question page top navigation bar (including timer and stopwatch…
aasmal97 Oct 22, 2023
5ff08b5
modified icon inside timers, so width and height are stable during tr…
aasmal97 Oct 22, 2023
21ae051
made navigation bar for question page responsive
aasmal97 Oct 22, 2023
8d63c00
fixed user profile sizing bug where it couldnt be consistent on mobil…
aasmal97 Oct 22, 2023
663ca2a
added additional styles to navbar menu icon
aasmal97 Oct 22, 2023
273803e
adjusted icon styling to not shift when being triggered
aasmal97 Oct 22, 2023
33a3ae9
added styling to buttons
aasmal97 Oct 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
965 changes: 956 additions & 9 deletions studyAi/package-lock.json

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions studyAi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"prisma": "npx prisma generate "
},
"dependencies": {
"@emotion/react": "^11.11.1",
Expand All @@ -18,15 +19,25 @@
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@mui/material": "^5.14.12",
"@next-auth/prisma-adapter": "^1.0.7",
"@prisma/client": "^5.4.2",
"axios": "^1.5.1",
"bcryptjs": "^2.4.3",
"dotenv": "^16.3.1",
"lodash": "^4.17.21",
"mongodb": "^6.1.0",
"moongoose": "^0.0.5",
"mssql": "^10.0.1",
"next": "13.5.4",
"next-auth": "^4.23.2",
"react": "18",
"react-dom": "18"
"react-dom": "18",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/bcryptjs": "^2.4.5",
"@types/lodash": "^4.14.199",
"@types/mongoose": "^5.11.97",
"@types/mssql": "^9.1.1",
"@types/node": "20",
"@types/react": "18",
Expand Down
110 changes: 110 additions & 0 deletions studyAi/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
type QuestionData{
title String
description String
}
type AnswerData{
answer String
}
type LikeCounter {
likes Int
dislikes Int
}
model Question {
id String @id @default(auto()) @map("_id") @db.ObjectId
creatorId String
type String
tags String[]
question QuestionData
answer AnswerData
dateCreated DateTime @default(now())
likeCounter LikeCounter
}

model QuestionLikes {
id String @id @default(auto()) @map("_id") @db.ObjectId
dateCreated DateTime @default(now())
userId String @unique @db.ObjectId
questionId String @unique @db.ObjectId
}
model Quiz {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
tags String
likes Int
creatorId String @unique @db.ObjectId
questionIds String[]
dateCreated DateTime @default(now())
}
model QuizLikes {
id String @id @default(auto()) @map("_id") @db.ObjectId
dateCreated DateTime @default(now())
userId String @unique @db.ObjectId
questionId String @unique @db.ObjectId
}
model Submissions {
id String @id @default(auto()) @map("_id") @db.ObjectId
time DateTime @default(now())
score Int
dateCreated DateTime @default(now())
userId String @unique @db.ObjectId
quizId String @unique @db.ObjectId
}

model UserCredentials{
id String @id @default(auto()) @map("_id") @db.ObjectId
userId String @unique @db.ObjectId
email String @unique
password String?
provider String
}
model Account {
id String @id @default(auto()) @map("_id") @db.ObjectId
userId String @unique @db.ObjectId
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)

@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(auto()) @map("_id") @db.ObjectId
sessionToken String @unique
userId String @db.ObjectId
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
email String @unique
usersReached Int @default(0)
dateCreated DateTime @default(now())
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model VerificationToken {
id String @id @default(auto()) @map("_id") @db.ObjectId
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
2 changes: 1 addition & 1 deletion studyAi/scripts/generateEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const main = async () => {
await delay(500);
const value = runCommand(`vlt secrets get --plaintext ${str}`);
if (!value) return null;
return str + "=" + value;
return str + "=" + `"${value.replace("\n", "")}"\n`;
});
const contentArr = await Promise.all(contentArrPromise);
//log all errors from secrets
Expand Down
52 changes: 52 additions & 0 deletions studyAi/src/app/api/auth/[...nextauth]/funcs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
connectToDb,
findUniqueByEmail,
prismaDb,
} from "@/app/util/prisma/helpers";
import { Profile, Account } from "next-auth";
export const addCredDoc = async ({
profile,
account,
isNewUser,
}: {
account: Account | null;
profile?: Profile | undefined;
isNewUser?: boolean | undefined;
}) => {
if (!isNewUser) return;
//procced only if new user
if (!profile) return;
//for Oauth provider mapping to db
try {
const { email, name } = profile;
if (!email || !name) return;
await connectToDb();
const [user, userDoc] = await Promise.all([
findUniqueByEmail(email, "userCredentials"),
findUniqueByEmail(email, "user"),
]);
if (account && account.userId && !user)
return await prismaDb.userCredentials.create({
data: {
userId: account.userId,
email,
provider: "oauth",
},
});
//this only occurs when oauth is typically used,
//since sign with email and pw already
//has the cred file created
if (userDoc && !user)
return await prismaDb.userCredentials.create({
data: {
userId: userDoc.id,
email,
provider: "oauth",
},
});
} catch (err) {
console.error(err);
} finally {
prismaDb.$disconnect();
}
};
146 changes: 102 additions & 44 deletions studyAi/src/app/api/auth/[...nextauth]/options.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,103 @@
import type { NextAuthOptions } from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'
import CredentialsProvider from 'next-auth/providers/credentials'

import type { NextAuthOptions } from "next-auth";
import bcrypt from "bcryptjs";
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import {
connectToDb,
findUniqueByEmail,
findUniqueById,
prismaDb,
} from "@/app/util/prisma/helpers";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { addCredDoc } from "./funcs";
export const options: NextAuthOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
}),
CredentialsProvider({
name: 'Credentials',
credentials: {
email: {
label: 'Email:',
type: 'text',
placeholder: 'email'
},
password: {
label: 'Password:',
type: "password",
placeholder: "password"
}
},
async authorize(credentials) {
const user = {
id: "1",
email: "admin@studyai.com",
password: "studyai"
}

if (credentials?.email === user.email && credentials?.password === user.password) {
console.log(user.email, user.password)
return user
} else {
return null
}
},
}),
],
pages: {
signIn: '/../../../auth/login/page',
newUser: '/../../../auth/signup/page',
}
}
adapter: PrismaAdapter(prismaDb),
session: {
strategy: "jwt",
},
jwt: {
secret: process.env.NEXTAUTH_SECRET as string,
},
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
}),
CredentialsProvider({
name: "Credentials",
credentials: {
email: {
label: "Email",
type: "text",
placeholder: "email",
},
password: {
label: "Password",
type: "password",
placeholder: "password",
},
},
async authorize(credentials, req) {
try {
// check to see if email and password is there
if (!credentials?.email || !credentials.password) {
throw new Error("Please enter an email and password");
}
await connectToDb();
const user = await findUniqueByEmail(
credentials.email,
"userCredentials"
);
//if no user was found
if (!user || !user?.password) throw new Error("No user found");
// // check to see if password matches
const passwordMatch = await bcrypt.compare(
credentials.password,
user.password
);
// if password does not match
if (!passwordMatch) throw new Error("Incorrect password");
const userId = user.userId;
const userInfo = await findUniqueById(userId, "user");
return userInfo;
} catch (err) {
console.error(err);
return null;
} finally {
prismaDb.$disconnect();
}
},
}),
],
pages: {
signIn: "/../../../auth/login/page",
error: "/../../../auth/login/page",
},
callbacks: {
async session({ session }) {
try {
await connectToDb();
const sessionCreds = await findUniqueByEmail(
session.user.email,
"userCredentials"
);
if (!sessionCreds) return session;
const sessionUser = await findUniqueById(sessionCreds.userId, "user");
if (!sessionUser) return session;
session.user = sessionUser;
return session;
} catch (err) {
console.error(err);
return session;
} finally {
prismaDb.$disconnect();
}
},
},
events: {
//create a user document on oauth sign in
signIn: async ({ profile, account, isNewUser }) => {
await addCredDoc({ profile, account, isNewUser });
},
},
};
14 changes: 9 additions & 5 deletions studyAi/src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import NextAuth from 'next-auth'
import { options } from './options'
import NextAuth from "next-auth";
import { options } from "./options";
const env = process.env.NODE_ENV;
if (env === "development")
process.env.NEXTAUTH_URL = process.env.NEXT_AUTH_URL_DEV;
//for prod
else process.env.NEXTAUTH_URL = process.env.NEXTAUTH_URL;
const handler = NextAuth(options);

const handler = NextAuth(options)

export {handler as GET, handler as POST}
export { handler as GET, handler as POST };
16 changes: 0 additions & 16 deletions studyAi/src/app/api/seed/route.ts

This file was deleted.

Loading