Spaces:
Sleeping
Sleeping
Commit
·
e9a4fe2
1
Parent(s):
d9826a8
feat(api): add auth/onboarding endpoint
Browse files- app/main.py +70 -16
- app/main.py:Zone.Identifier +0 -0
- app/models.py +14 -0
- app/models.py:Zone.Identifier +0 -0
- app/services.py:Zone.Identifier +0 -0
- app/utils.py:Zone.Identifier +0 -0
- requirements.txt +6 -5
- requirements.txt:Zone.Identifier +0 -0
app/main.py
CHANGED
|
@@ -2,13 +2,16 @@ import os
|
|
| 2 |
import sendgrid
|
| 3 |
from sendgrid.helpers.mail import Mail
|
| 4 |
from fastapi import FastAPI, HTTPException, Query
|
|
|
|
| 5 |
from supabase import create_client
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
-
from datetime import datetime, timedelta
|
|
|
|
| 8 |
|
| 9 |
from app.utils import *
|
| 10 |
from app.models import *
|
| 11 |
-
from app.services import get_candidates
|
|
|
|
| 12 |
|
| 13 |
|
| 14 |
load_dotenv()
|
|
@@ -32,6 +35,13 @@ JWT_EXPIRES_IN = os.getenv("JWT_EXPIRES_IN")
|
|
| 32 |
|
| 33 |
|
| 34 |
app = FastAPI()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
|
| 37 |
@app.post("/auth/send-verification")
|
|
@@ -53,15 +63,15 @@ def send_verification(data: EmailRequest):
|
|
| 53 |
)
|
| 54 |
|
| 55 |
if last_code.data:
|
| 56 |
-
created_at =
|
| 57 |
-
diff = datetime.
|
| 58 |
|
| 59 |
if diff.total_seconds() < 60:
|
| 60 |
raise HTTPException(status_code=429, detail="Demasiados intentos, espera 60 segundos")
|
| 61 |
|
| 62 |
# Generate verification code
|
| 63 |
code = generate_code()
|
| 64 |
-
expires_at = datetime.
|
| 65 |
|
| 66 |
# Store code in the database
|
| 67 |
supabase.table("auth_code").delete().eq("email", email).execute()
|
|
@@ -113,8 +123,8 @@ def verify(data: VerifyRequest):
|
|
| 113 |
raise HTTPException(status_code=400, detail="Código inválido")
|
| 114 |
|
| 115 |
# Verify if the code has expired
|
| 116 |
-
expires_at =
|
| 117 |
-
if datetime.
|
| 118 |
raise HTTPException(status_code=400, detail="Código expirado")
|
| 119 |
|
| 120 |
# Get or create user
|
|
@@ -135,7 +145,7 @@ def verify(data: VerifyRequest):
|
|
| 135 |
return {
|
| 136 |
"success": True,
|
| 137 |
"user": {
|
| 138 |
-
"id":
|
| 139 |
"email": user["email"],
|
| 140 |
"firstName": None,
|
| 141 |
"lastName": None,
|
|
@@ -149,22 +159,66 @@ def verify(data: VerifyRequest):
|
|
| 149 |
return {
|
| 150 |
"success": True,
|
| 151 |
"user": {
|
| 152 |
-
"id":
|
| 153 |
"email": user['email'],
|
| 154 |
-
"firstName": user['
|
| 155 |
-
"lastName": user['
|
| 156 |
-
"onboardingCompleted": user['
|
| 157 |
}
|
| 158 |
}
|
| 159 |
|
| 160 |
|
| 161 |
-
@app.post("/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
def match_candidate(
|
| 163 |
-
|
| 164 |
limit: int = Query(20),
|
| 165 |
offset: int = Query(0)
|
| 166 |
):
|
| 167 |
-
user_id = data.user_id
|
| 168 |
return get_candidates(user_id, limit=limit, offset=offset, supabase=supabase)
|
| 169 |
|
| 170 |
|
|
@@ -339,7 +393,7 @@ def respond_match(
|
|
| 339 |
}
|
| 340 |
|
| 341 |
if action == "accept":
|
| 342 |
-
update_data["accepted_at"] = datetime.
|
| 343 |
|
| 344 |
update_res = (
|
| 345 |
supabase.table("matches")
|
|
|
|
| 2 |
import sendgrid
|
| 3 |
from sendgrid.helpers.mail import Mail
|
| 4 |
from fastapi import FastAPI, HTTPException, Query
|
| 5 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 6 |
from supabase import create_client
|
| 7 |
from dotenv import load_dotenv
|
| 8 |
+
from datetime import datetime, timedelta, timezone
|
| 9 |
+
from dateutil.parser import isoparse
|
| 10 |
|
| 11 |
from app.utils import *
|
| 12 |
from app.models import *
|
| 13 |
+
from app.services import get_candidates
|
| 14 |
+
|
| 15 |
|
| 16 |
|
| 17 |
load_dotenv()
|
|
|
|
| 35 |
|
| 36 |
|
| 37 |
app = FastAPI()
|
| 38 |
+
app.add_middleware(
|
| 39 |
+
CORSMiddleware,
|
| 40 |
+
allow_origins=["*"],
|
| 41 |
+
allow_credentials=True,
|
| 42 |
+
allow_methods=["*"],
|
| 43 |
+
allow_headers=["*"],
|
| 44 |
+
)
|
| 45 |
|
| 46 |
|
| 47 |
@app.post("/auth/send-verification")
|
|
|
|
| 63 |
)
|
| 64 |
|
| 65 |
if last_code.data:
|
| 66 |
+
created_at = isoparse(last_code.data[0]["created_at"])
|
| 67 |
+
diff = datetime.now(timezone.utc) - created_at
|
| 68 |
|
| 69 |
if diff.total_seconds() < 60:
|
| 70 |
raise HTTPException(status_code=429, detail="Demasiados intentos, espera 60 segundos")
|
| 71 |
|
| 72 |
# Generate verification code
|
| 73 |
code = generate_code()
|
| 74 |
+
expires_at = datetime.now(timezone.utc) + timedelta(seconds=int(JWT_EXPIRES_IN))
|
| 75 |
|
| 76 |
# Store code in the database
|
| 77 |
supabase.table("auth_code").delete().eq("email", email).execute()
|
|
|
|
| 123 |
raise HTTPException(status_code=400, detail="Código inválido")
|
| 124 |
|
| 125 |
# Verify if the code has expired
|
| 126 |
+
expires_at = isoparse(record.data[0]["expires_at"])
|
| 127 |
+
if datetime.now(timezone.utc) > expires_at:
|
| 128 |
raise HTTPException(status_code=400, detail="Código expirado")
|
| 129 |
|
| 130 |
# Get or create user
|
|
|
|
| 145 |
return {
|
| 146 |
"success": True,
|
| 147 |
"user": {
|
| 148 |
+
"id": user['id'],
|
| 149 |
"email": user["email"],
|
| 150 |
"firstName": None,
|
| 151 |
"lastName": None,
|
|
|
|
| 159 |
return {
|
| 160 |
"success": True,
|
| 161 |
"user": {
|
| 162 |
+
"id": user['id'],
|
| 163 |
"email": user['email'],
|
| 164 |
+
"firstName": user['firstname'],
|
| 165 |
+
"lastName": user['lastname'],
|
| 166 |
+
"onboardingCompleted": user['onboardingcompleted']
|
| 167 |
}
|
| 168 |
}
|
| 169 |
|
| 170 |
|
| 171 |
+
@app.post("/auth/onboarding")
|
| 172 |
+
def onboarding(data: OnboardingRequest):
|
| 173 |
+
# Data for User Table
|
| 174 |
+
firstName = data.firstName
|
| 175 |
+
lastName = data.lastName
|
| 176 |
+
university = data.university
|
| 177 |
+
career = data.career
|
| 178 |
+
semester = data.semester
|
| 179 |
+
|
| 180 |
+
# Data for UserProfile Table
|
| 181 |
+
user_id = data.user_id
|
| 182 |
+
strengths = data.strengths
|
| 183 |
+
weaknesses = data.weaknesses
|
| 184 |
+
studyStyle = data.studyStyle
|
| 185 |
+
careerInterests = data.careerInterests
|
| 186 |
+
futureRoles = data.futureRoles
|
| 187 |
+
skillsToLearn = data.skillsToLearn
|
| 188 |
+
|
| 189 |
+
# Update User Table
|
| 190 |
+
supabase.table("users").update({
|
| 191 |
+
"firstname": firstName,
|
| 192 |
+
"lastname": lastName,
|
| 193 |
+
"university": university,
|
| 194 |
+
"career": career,
|
| 195 |
+
"semester": semester,
|
| 196 |
+
"onboardingcompleted": True
|
| 197 |
+
}).eq("id", user_id).execute()
|
| 198 |
+
|
| 199 |
+
# Update UserProfile Table
|
| 200 |
+
supabase.table("user_profiles").insert({
|
| 201 |
+
"user_id": user_id,
|
| 202 |
+
"strengths": strengths,
|
| 203 |
+
"weaknesses": weaknesses,
|
| 204 |
+
"studystyle": studyStyle,
|
| 205 |
+
"careerinterests": careerInterests,
|
| 206 |
+
"futureroles": futureRoles,
|
| 207 |
+
"skillstolearn": skillsToLearn
|
| 208 |
+
}).execute()
|
| 209 |
+
|
| 210 |
+
return {
|
| 211 |
+
"success": True,
|
| 212 |
+
"message": "Onboarding completed successfully"
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
@app.get("/matches/candidates")
|
| 217 |
def match_candidate(
|
| 218 |
+
user_id: int = Query(...),
|
| 219 |
limit: int = Query(20),
|
| 220 |
offset: int = Query(0)
|
| 221 |
):
|
|
|
|
| 222 |
return get_candidates(user_id, limit=limit, offset=offset, supabase=supabase)
|
| 223 |
|
| 224 |
|
|
|
|
| 393 |
}
|
| 394 |
|
| 395 |
if action == "accept":
|
| 396 |
+
update_data["accepted_at"] = datetime.now(timezone.utc).isoformat()
|
| 397 |
|
| 398 |
update_res = (
|
| 399 |
supabase.table("matches")
|
app/main.py:Zone.Identifier
ADDED
|
Binary file (25 Bytes). View file
|
|
|
app/models.py
CHANGED
|
@@ -8,6 +8,20 @@ class VerifyRequest(BaseModel):
|
|
| 8 |
email: EmailStr
|
| 9 |
code: str
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
class UserRequest(BaseModel):
|
| 12 |
user_id: int
|
| 13 |
|
|
|
|
| 8 |
email: EmailStr
|
| 9 |
code: str
|
| 10 |
|
| 11 |
+
class OnboardingRequest(BaseModel):
|
| 12 |
+
user_id: int
|
| 13 |
+
firstName: Optional[str] = None
|
| 14 |
+
lastName: Optional[str] = None
|
| 15 |
+
university: Optional[str] = None
|
| 16 |
+
career: Optional[str] = None
|
| 17 |
+
semester: Optional[int] = None
|
| 18 |
+
strengths: Optional[list] = None
|
| 19 |
+
weaknesses: Optional[list] = None
|
| 20 |
+
studyStyle: Optional[str] = None
|
| 21 |
+
careerInterests: Optional[list] = None
|
| 22 |
+
futureRoles: Optional[list] = None
|
| 23 |
+
skillsToLearn: Optional[list] = None
|
| 24 |
+
|
| 25 |
class UserRequest(BaseModel):
|
| 26 |
user_id: int
|
| 27 |
|
app/models.py:Zone.Identifier
ADDED
|
Binary file (25 Bytes). View file
|
|
|
app/services.py:Zone.Identifier
ADDED
|
Binary file (25 Bytes). View file
|
|
|
app/utils.py:Zone.Identifier
ADDED
|
Binary file (25 Bytes). View file
|
|
|
requirements.txt
CHANGED
|
@@ -31,13 +31,14 @@ sendgrid
|
|
| 31 |
pydantic
|
| 32 |
email-validator
|
| 33 |
|
| 34 |
-
# -----------------------------
|
| 35 |
-
# 📨 Optional: Email Templates (HTML)
|
| 36 |
-
# -----------------------------
|
| 37 |
-
jinja2
|
| 38 |
-
|
| 39 |
# -----------------------------
|
| 40 |
# 🤖 Artificial Intelligence Integration
|
| 41 |
# -----------------------------
|
| 42 |
torch
|
| 43 |
sentence-transformers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
pydantic
|
| 32 |
email-validator
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
# -----------------------------
|
| 35 |
# 🤖 Artificial Intelligence Integration
|
| 36 |
# -----------------------------
|
| 37 |
torch
|
| 38 |
sentence-transformers
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# -----------------------------
|
| 42 |
+
# 🕰️ Date and Time Handling
|
| 43 |
+
# -----------------------------
|
| 44 |
+
python-dateutil
|
requirements.txt:Zone.Identifier
ADDED
|
Binary file (25 Bytes). View file
|
|
|