|
@@ -12,7 +12,7 @@ import locales
|
|
|
from dependencies import get_current_user, require_admin
|
|
from dependencies import get_current_user, require_admin
|
|
|
import config
|
|
import config
|
|
|
import secrets
|
|
import secrets
|
|
|
-from services.email_service import send_verification_email
|
|
|
|
|
|
|
+from services.email_service import send_verification_email, send_password_reset_email
|
|
|
|
|
|
|
|
try:
|
|
try:
|
|
|
from google.oauth2 import id_token
|
|
from google.oauth2 import id_token
|
|
@@ -178,22 +178,33 @@ async def logout(user: dict = Depends(get_current_user)):
|
|
|
return {"message": "Successfully logged out"}
|
|
return {"message": "Successfully logged out"}
|
|
|
|
|
|
|
|
@router.post("/forgot-password")
|
|
@router.post("/forgot-password")
|
|
|
-async def forgot_password(request: schemas.ForgotPassword):
|
|
|
|
|
- user = db.execute_query("SELECT id FROM users WHERE email = %s", (request.email,))
|
|
|
|
|
|
|
+async def forgot_password(request: schemas.ForgotPassword, lang: str = "en"):
|
|
|
|
|
+ user = db.execute_query("SELECT id, preferred_language FROM users WHERE email = %s", (request.email,))
|
|
|
if not user: raise HTTPException(status_code=404, detail="Email not found")
|
|
if not user: raise HTTPException(status_code=404, detail="Email not found")
|
|
|
- token = str(uuid.uuid4())
|
|
|
|
|
- expires_at = datetime.utcnow() + timedelta(minutes=15)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ token = secrets.token_urlsafe(32)
|
|
|
|
|
+ expires_at = datetime.utcnow() + timedelta(minutes=10)
|
|
|
db.execute_commit("INSERT INTO password_reset_tokens (user_id, token, expires_at) VALUES (%s, %s, %s)", (user[0]['id'], token, expires_at))
|
|
db.execute_commit("INSERT INTO password_reset_tokens (user_id, token, expires_at) VALUES (%s, %s, %s)", (user[0]['id'], token, expires_at))
|
|
|
- return {"message": "Reset instructions sent to your email", "demo_token": token}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Send Email
|
|
|
|
|
+ user_lang = user[0]['preferred_language'] or lang
|
|
|
|
|
+ send_password_reset_email(request.email, token, user_lang)
|
|
|
|
|
+
|
|
|
|
|
+ return {"message": "Reset instructions sent to your email"}
|
|
|
|
|
|
|
|
@router.post("/reset-password")
|
|
@router.post("/reset-password")
|
|
|
async def reset_password(request: schemas.ResetPassword):
|
|
async def reset_password(request: schemas.ResetPassword):
|
|
|
reset_data = db.execute_query("SELECT user_id, expires_at FROM password_reset_tokens WHERE token = %s", (request.token,))
|
|
reset_data = db.execute_query("SELECT user_id, expires_at FROM password_reset_tokens WHERE token = %s", (request.token,))
|
|
|
if not reset_data: raise HTTPException(status_code=400, detail="Invalid token")
|
|
if not reset_data: raise HTTPException(status_code=400, detail="Invalid token")
|
|
|
if reset_data[0]['expires_at'] < datetime.utcnow(): raise HTTPException(status_code=400, detail="Token expired")
|
|
if reset_data[0]['expires_at'] < datetime.utcnow(): raise HTTPException(status_code=400, detail="Token expired")
|
|
|
|
|
+
|
|
|
|
|
+ user_id = reset_data[0]['user_id']
|
|
|
hashed_password = auth_utils.get_password_hash(request.new_password)
|
|
hashed_password = auth_utils.get_password_hash(request.new_password)
|
|
|
- db.execute_commit("UPDATE users SET password_hash = %s WHERE id = %s", (hashed_password, reset_data[0]['user_id']))
|
|
|
|
|
- db.execute_commit("DELETE FROM password_reset_tokens WHERE token = %s", (request.token,))
|
|
|
|
|
|
|
+ db.execute_commit("UPDATE users SET password_hash = %s WHERE id = %s", (hashed_password, user_id))
|
|
|
|
|
+
|
|
|
|
|
+ # IMPORTANT: Delete ALL tokens for this user after successful reset
|
|
|
|
|
+ db.execute_commit("DELETE FROM password_reset_tokens WHERE user_id = %s", (user_id,))
|
|
|
|
|
+
|
|
|
return {"message": "Password reset successfully"}
|
|
return {"message": "Password reset successfully"}
|
|
|
|
|
|
|
|
@router.get("/me", response_model=schemas.UserResponse)
|
|
@router.get("/me", response_model=schemas.UserResponse)
|