Skip to content

Commit

Permalink
feat: set up database and auth (#178)
Browse files Browse the repository at this point in the history
Co-authored-by: Cyro292 <[email protected]>
Co-authored-by: simonhng <[email protected]>
Co-authored-by: Behsad Riemer <[email protected]>
  • Loading branch information
4 people authored Dec 19, 2023
1 parent b06e238 commit c7fca61
Show file tree
Hide file tree
Showing 29 changed files with 2,125 additions and 845 deletions.
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:20-alpine

WORKDIR /space

COPY . .

RUN cd app && apk add --no-cache make gcc g++ python3 py3-pip && \
npm install && \
npm rebuild bcrypt --build-from-source && \
apk del make gcc g++ python3 py3-pip

WORKDIR /space/app

ENTRYPOINT ["sh", "entrypoint.sh"]
5 changes: 4 additions & 1 deletion app/.env.example
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
DATABASE_URL=postgres://postgres:password@localhost:15432/spacedb
NEXT_PUBLIC_ENVIRONMENT=development
NEXT_PUBLIC_API_URL=https://localhost:8000/
NEXTAUTH_URL=https://localhost:3000
DATABASE_URL=postgres://postgres:password@localhost:15432/spacedb
2 changes: 2 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

certificates
148 changes: 148 additions & 0 deletions app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,154 @@ You can start editing the page by modifying `app/page.tsx`. The page auto-update

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Model

```mermaid
erDiagram
Account ||--o{ User : ""
Account {
String id PK
String userId FK
String type
String provider
String providerAccountId
Boolean ok
String state
String refresh_token
String access_token
Int expires_at
String token_type
String scope
String id_token
DateTime createdAt
DateTime updatedAt
String session_state
}
Session ||--o{ User : ""
Session {
String id PK
String sessionToken
String userId FK
DateTime expires
DateTime createdAt
DateTime updatedAt
}
User ||--|{ VerificationToken : ""
User ||--o{ Profile : ""
User ||--o{ DepartmentMembership : ""
User ||--o{ Opportunity : ""
User ||--o{ OpportunityParticipation : ""
User ||--o{ Review : ""
User ||--o{ Account : ""
User ||--o{ Session : ""
User {
String id PK
Int profileId FK
String email
String password
String first_name
String last_name
String image
UserPermission permission
DateTime emailVerified
DateTime createdAt
DateTime updatedAt
}
VerificationToken {
String id PK
String identifier
String token
DateTime expires
DateTime createdAt
DateTime updatedAt
}
Profile ||--|{ Contact : ""
Profile ||--o{ User : ""
Profile {
Int id PK
Int userId FK
DateTime birthday
String nationality
String description
String activity_status
String degree_level
String degree_name
Int degree_semester
DateTime degree_last_update
String university
String profile_picture
DateTime createdAt
DateTime updatedAt
}
Contact {
Int id PK
Int profileId FK
ContactType type
String username
DateTime createdAt
DateTime updatedAt
}
Department ||--|{ DepartmentMembership : ""
Department ||--|{ Opportunity : ""
Department {
Int id PK
String name
DepartmentType type
DateTime creation_date
DateTime createdAt
DateTime updatedAt
}
DepartmentMembership {
Int id PK
String userId FK
Int departmentId FK
DateTime membership_start
DateTime membership_end
DepartmentPosition department_position
DateTime createdAt
DateTime updatedAt
}
Opportunity ||--|{ Review : ""
Opportunity ||--|{ OpportunityParticipation : ""
Opportunity {
Int id PK
String creatorId FK
String title
String description
Int departmentId FK
DateTime opportunity_start
DateTime opportunity_end
DateTime createdAt
DateTime updatedAt
}
OpportunityParticipation {
String userId FK
Int opportunityId FK
OpportunityPermission permission
DateTime createdAt
DateTime updatedAt
}
Review {
Int id PK
Int opportunityId FK
Int assigneeId FK
String review_text
Json content
DateTime createdAt
DateTime updatedAt
}
```

## Learn More

To learn more about Next.js, take a look at the following resources:
Expand Down
109 changes: 109 additions & 0 deletions app/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { NextAuthOptions } from "next-auth";
import NextAuth from "next-auth/next";
import SlackProvider from "next-auth/providers/slack";
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import prisma from "database/db";
import CredentialsProvider from "next-auth/providers/credentials";
import EmailProvider from "next-auth/providers/email";
import { compare } from "bcrypt";

export const authOptions: NextAuthOptions = {
session:{
strategy:"jwt",
maxAge: 30 * 24 * 60 * 60 //30 days
},
adapter: PrismaAdapter(prisma),
secret: process.env.NEXTAUTH_SECRET,
pages: {
signIn: '/auth',
/*
newUser: '/auth/signup',
signOut: '/auth/signout',
error: '/auth/error', // Error code passed in query string as ?error=
verifyRequest: '/auth/verify-request', // (used for check email message)
*/
//TODO: add signOut, error pages
},
providers: [
SlackProvider(
{
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
profile(profile, tokens) {
return {
id: profile["https://slack.com/user_id"] || profile.sub,
email: profile.email,
image: profile.picture,
first_name: profile.given_name,
permission: 'member',
last_name: profile.family_name,
emailVerified: profile.date_email_verified
};
},
},
),
//TODO: add email provider setup
CredentialsProvider({
name: "Credentials",
credentials: {
email: { label: "Email", type: "email", placeholder: "[email protected]" },
password: { label: "Password", type: "password" }
},
async authorize(credentials) {
if(!credentials?.email || !credentials?.password) {
return null;
}

const existingUser = await prisma.user.findUnique({
where: { email : credentials?.email }
});

if(!existingUser) {
return null;
}

const passwordMatch = await compare(credentials.password, existingUser.password);

if(!passwordMatch) {
return null;
}

return {
id: `${existingUser.id}`,
username: existingUser.first_name + "_" + existingUser.last_name, //do we really need this here?
email: existingUser.email
}
}
}),
// EmailProvider({
// server: process.env.EMAIL_SERVER,
// from: process.env.EMAIL_FROM
// }),
],
callbacks:{
async jwt({token,user}){
return{...token,...user}
},
async session({session,token}){
return {
...session,
user : {
...session.user,
id: token.id,
first_name: token.first_name,
permission: token.permission,
image: token.image,
}
}
// session.user.id = token.id
// session.user.first_name = token.first_name
// session.user.permission = token.permission
// session.user.image = token.image
// return session
}
}
}

const handler = NextAuth(authOptions)

export {handler as GET, handler as POST}
32 changes: 32 additions & 0 deletions app/app/api/auth/signup/signup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NextResponse } from 'next/server';
import db from '../../../../database/db';
import { hash } from 'bcrypt';



export default async function POST(req, res) {
try {
const { email, password } = req.body;
console.log(email, password);
const existingUser = await db.user.findUnique({
where: { email : email }
});
if (!existingUser) {
return NextResponse.json({ error: 'User with this email already exists' }, { status: 409 });
}

const hashedPassword = await hash(password, 10);

// const newUser = await db.user.create({
// data: {
// email: email,
// password: hashedPassword
// //TODO: add other fields
// }
// });

return NextResponse.json({ message: 'User created' }, { status: 201 });
} catch (error) {
return NextResponse.json({ error: 'Something went wrong' }, { status: 500 });
}
}
Loading

0 comments on commit c7fca61

Please sign in to comment.