e
File size: 3,652 Bytes
a17af42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""
app/routes/auth.py
Auth endpoints: OTP request, OTP verify, logout, profile.
Wraps app/services/auth.py logic.
"""
import logging
from fastapi import APIRouter, Request, Form, HTTPException
from fastapi.responses import JSONResponse
from app.services.auth import (
    send_email_otp, verify_email_otp,
    create_session, revoke_session, get_user_from_token,
)
from app.models.db import db_conn

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/auth", tags=["auth"])


@router.post("/request-otp")
async def request_otp(email: str = Form(...)):
    """Send a 6-digit OTP to the user's email. Dev mode: returns OTP in response."""
    try:
        otp = send_email_otp(email)
        return JSONResponse({
            "sent"   : True,
            "message": "OTP sent. Check your email.",
            # Remove next line in production — only for dev/HF testing
            "_dev_otp": otp,
        })
    except Exception as exc:
        logger.error("OTP request failed: %s", exc)
        raise HTTPException(status_code=500, detail="Could not send OTP")


@router.post("/verify-otp")
async def verify_otp(
    request: Request,
    email: str = Form(...),
    otp  : str = Form(...),
):
    """Verify OTP. Returns session token on success."""
    user = verify_email_otp(email, otp)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid or expired OTP")
    device_hint = request.headers.get("user-agent", "")[:100]
    token       = create_session(user["id"], device_hint)
    return JSONResponse({
        "token"   : token,
        "user_id" : user["id"],
        "email"   : user.get("email", ""),
        "is_pro"  : bool(user.get("is_pro", 0)),
        "message" : "Login successful",
    })


@router.post("/logout")
async def logout(request: Request):
    """Revoke the current session token."""
    auth  = request.headers.get("Authorization", "")
    token = auth.removeprefix("Bearer ").strip() if auth.startswith("Bearer ") else None
    if token:
        revoke_session(token)
    return JSONResponse({"logged_out": True})


@router.get("/me")
async def get_me(request: Request):
    """Return current user profile from Bearer token."""
    auth  = request.headers.get("Authorization", "")
    token = auth.removeprefix("Bearer ").strip() if auth.startswith("Bearer ") else None
    user  = get_user_from_token(token) if token else None
    if not user:
        raise HTTPException(status_code=401, detail="Not authenticated")
    return JSONResponse({
        "user_id"    : user["id"],
        "email"      : user.get("email", ""),
        "name"       : user.get("name", ""),
        "is_pro"     : bool(user.get("is_pro", 0)),
        "streak_days": user.get("streak_days", 0),
        "persona"    : user.get("persona", "General Adult"),
        "language"   : user.get("language", "en"),
    })


@router.put("/profile")
async def update_profile(
    request : Request,
    name    : str   = Form(""),
    persona : str   = Form("General Adult"),
    language: str   = Form("en"),
    tdee    : float = Form(2000),
):
    """Update user profile fields."""
    auth  = request.headers.get("Authorization", "")
    token = auth.removeprefix("Bearer ").strip() if auth.startswith("Bearer ") else None
    user  = get_user_from_token(token) if token else None
    if not user:
        raise HTTPException(status_code=401, detail="Not authenticated")
    with db_conn() as conn:
        conn.execute(
            "UPDATE users SET name=?, persona=?, language=?, tdee=? WHERE id=?",
            (name, persona, language, tdee, user["id"])
        )
    return JSONResponse({"updated": True})