Rauhan's picture
UPLOAD
69601d4
from ..models.requestModels import SignUp, Login, LoginWithProvider, OnboardingDetails, NewCredentials
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from fastapi import APIRouter, HTTPException, Depends
from supabase.lib.client_options import ClientOptions
from fastapi.responses import JSONResponse
from ..utils.functions import verifyToken
from supabase import create_client
from typing import Annotated
from jose import jwt
import pandas as pd
import datetime
import hashlib
import os
router = APIRouter()
security = HTTPBearer()
client = create_client(
supabase_url = os.environ["SUPABASE_URL"],
supabase_key = os.environ["SUPABASE_KEY"],
options=ClientOptions(
auto_refresh_token=False,
persist_session=False,
)
)
@router.post("/signUp")
async def signup(signupDetails: SignUp):
try:
passwordString = signupDetails.password + os.environ["SECRET_KEY"]
hashedPassword = hashlib.md5(passwordString.encode("utf-8")).hexdigest()
allUsers = list()
page = 1
while True:
response = client.auth.admin.list_users(page = page, per_page = 1000)
if response == []:
break
else:
allUsers.extend(response)
page += 1
allUsers = [x.email for x in allUsers]
if signupDetails.email not in allUsers:
response = client.auth.sign_up(
{"email": signupDetails.email, "password": hashedPassword}
)
client.table(table_name = "Users").insert(
{
"userId": response.user.id,
"email": signupDetails.email,
"password": hashedPassword
}
).execute()
return JSONResponse(status_code = 200, content = {"status": "SUCCESS", "userId": response.user.id})
else:
return JSONResponse(status_code = 409, content = {"status": "ERROR", "errorDetail": "User Already Exists"})
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")
@router.get("/confirmMail/{userId}")
async def confirmMail(userId: str):
try:
allUsers = list()
page = 1
while True:
response = client.auth.admin.list_users(page = page, per_page = 1000)
if response == []:
break
else:
allUsers.extend(response)
page += 1
email = list(filter(lambda x: True if x.id == userId else False, allUsers))[0].email
response = client.auth.resend({
"type": "signup",
"email": email,
"options": {
"email_redirect_to": "https://localhost:3000/login"
}
})
return JSONResponse(status_code = 200, content = {"status": "SUCCESS"})
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")
@router.post("/login")
async def login(loginDetails: Login):
try:
passwordString = loginDetails.password + os.environ["SECRET_KEY"]
hashedPassword = hashlib.md5(passwordString.encode("utf-8")).hexdigest()
allUsers = list()
page = 1
while True:
response = client.auth.admin.list_users(page = page, per_page = 1000)
if response == []:
break
else:
allUsers.extend(response)
page += 1
filteredResult = list(filter(lambda x: True if x.email == loginDetails.email else False, allUsers))
if filteredResult == []:
return JSONResponse(status_code = 404, content = {"status": "ERROR", "errorDetail": "User not found"})
elif filteredResult[0].user_metadata.get("email_verified") == False:
return JSONResponse(status_code = 401, content = {"status": "ERROR", "errorDetail": "Email not verified"})
else:
allData = pd.DataFrame(client.table("Users").select("userId", "email", "password", "onboarded").execute().data, columns = ["userId", "email", "password", "onboarded"])
dataSlice = allData[allData["email"] == loginDetails.email].iloc[0, :]
if dataSlice["password"] != hashedPassword:
return JSONResponse(status_code = 401, content = {"status": "ERROR", "errorDetail": "Invalid email or password"})
else:
sessionStartTime = str(datetime.datetime.utcnow())
dictItems = {
"userId": dataSlice["userId"],
"email": loginDetails.email,
"password": hashedPassword,
"sessionStartTime": sessionStartTime
}
accessToken = jwt.encode(dictItems, os.environ["SECRET_KEY"], "HS256")
client.table("Sessions").insert({
"userId": dataSlice["userId"],
"email": dataSlice["email"],
"accessToken": accessToken,
"sessionStartTime": sessionStartTime,
"lastActivity": sessionStartTime
}).execute()
response = {
"status": "SUCCESS",
"userId": dataSlice["userId"],
"email": dataSlice["email"],
"accessToken": accessToken,
"onboarded": int(dataSlice["onboarded"])
}
return JSONResponse(status_code = 200, content = response)
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")
@router.post("/loginWithProvider")
async def loginWithProvider(loginDetails: LoginWithProvider):
try:
passwordString = str(loginDetails.sub) + str(loginDetails.id) + str(loginDetails.nodeId) + os.environ["SECRET_KEY"]
hashedPassword = hashlib.md5(passwordString.encode("utf-8")).hexdigest()
registeredUsers = pd.DataFrame(client.table("Users").select("userId", "email", "password", "onboarded").execute().data, columns = ["userId", "email", "password", "onboarded"])
if loginDetails.email not in registeredUsers["email"].unique():
response = client.table(table_name = "Users").insert(
{
"email": loginDetails.email,
"password": hashedPassword
}
).execute()
registeredUsers = pd.DataFrame(client.table("Users").select("userId", "email", "password", "onboarded").execute().data, columns = ["userId", "email", "password", "onboarded"])
else:
pass
dataSlice = registeredUsers[registeredUsers["email"] == loginDetails.email].iloc[0, :]
sessionStartTime = str(datetime.datetime.utcnow())
dictItems = {
"userId": dataSlice["userId"],
"email": loginDetails.email,
"password": hashedPassword,
"sessionStartTime": sessionStartTime
}
accessToken = jwt.encode(dictItems, os.environ["SECRET_KEY"], "HS256")
client.table("Sessions").insert({
"userId": dataSlice["userId"],
"email": dataSlice["email"],
"accessToken": accessToken,
"sessionStartTime": sessionStartTime,
"lastActivity": sessionStartTime
}).execute()
response = {
"status": "SUCCESS",
"userId": dataSlice["userId"],
"email": dataSlice["email"],
"accessToken": accessToken,
"onboarded": int(dataSlice["onboarded"])
}
return JSONResponse(status_code = 200, content = response)
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")
@router.post("/onboarding")
async def onboarding(onboardingDetails: OnboardingDetails, credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]):
try:
if verifyToken(token = credentials.credentials):
dataToUpdate = {
"onboarded": 1,
"usage": onboardingDetails.usage,
"fullName": onboardingDetails.fullName,
"role": onboardingDetails.role,
"companyName": onboardingDetails.companyName,
"industryType": onboardingDetails.industryType,
"companySize": onboardingDetails.companySize,
"country": onboardingDetails.country,
"goals": onboardingDetails.goals,
"source": onboardingDetails.source
}
response = client.table("Users").update(dataToUpdate).eq("email", onboardingDetails.email).execute()
return JSONResponse(status_code = 200, content = {"status": "SUCCESS", "message": "User onboarded successfully."})
else:
return JSONResponse(status_code = 498, content = {"status": "ERROR", "errorDetail": "Invalid Token"})
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")
@router.get("/initiatePasswordReset")
async def initiatePasswordReset(emailId: str):
try:
client.auth.reset_password_for_email(
emailId,
{
"redirect_to": "http://localhost:3000/login/create-new-password"
}
)
return JSONResponse(status_code = 200, content = {"status": "SUCCESS", "message": "Password reset initiated successfully."})
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")
@router.patch("/resetPassword")
async def resetPassword(email: str, newCredentials: NewCredentials):
try:
passwordString = newCredentials.newPassword + os.environ["SECRET_KEY"]
hashedPassword = hashlib.md5(passwordString.encode("utf-8")).hexdigest()
allUsers = list()
page = 1
while True:
response = client.auth.admin.list_users(page = page, per_page = 1000)
if response == []:
break
else:
allUsers.extend(response)
page += 1
filteredResult = list(filter(lambda x: True if x.email == email else False, allUsers))[0]
response = client.auth.admin.update_user_by_id(
filteredResult.id,
{"password": hashedPassword}
)
response = client.table("Users").update({"password": hashedPassword}).eq("email", email).execute()
return JSONResponse(status_code = 200, content = {"status": "SUCCESS", "message": "Password updated successfully!"})
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")
@router.get("/logout")
async def logout(credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]):
try:
if verifyToken(token = credentials.credentials):
response = client.table("Sessions").delete().eq("accessToken", credentials.credentials).execute()
return JSONResponse(status_code = 200, content = {"status": "SUCCESS", "message": "Session logged out successfully"})
else:
return JSONResponse(status_code = 498, content = {"status": "ERROR", "errorDetail": "Invalid Token"})
except Exception as e:
raise HTTPException(status_code = 500, detail = f"Endpoint says: {e}")