File size: 7,807 Bytes
763951b
 
1deefa3
325f578
5ed4a12
325f578
 
f24c2bb
325f578
f5ffa3e
1deefa3
9731a64
 
afd16c0
10b597c
afd16c0
10b597c
46a06f8
325f578
10b597c
625461f
e3afd2e
625461f
 
46a06f8
10b597c
625461f
 
 
 
 
10511db
 
 
 
 
 
325f578
44372ef
 
 
c5c4c92
8268a41
7c0b4d6
8268a41
c5c4c92
fab519b
 
7c0b4d6
c5c4c92
8268a41
 
 
 
09274a9
0e0e35e
bda9eb4
7c0b4d6
bda9eb4
cb6494b
b7bbd14
8d61206
 
17abc14
b7bbd14
8d61206
 
b7bbd14
8d61206
09274a9
 
 
 
 
8268a41
09274a9
 
 
 
 
e3afd2e
 
 
 
cb6494b
a3ea3d6
4da28a8
 
dcdcf2f
 
 
 
4da28a8
 
2a3fa0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dcdcf2f
4da28a8
377e020
473df3a
377e020
473df3a
 
44372ef
 
5ed4a12
dc39372
e007f86
dc39372
8338c06
e007f86
dc39372
e007f86
 
5ed4a12
e007f86
 
5ed4a12
 
 
 
c209774
1deefa3
fecefe5
 
1deefa3
 
 
 
 
 
ca1fdb8
 
 
 
 
1deefa3
3dc66e5
ca1fdb8
1deefa3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ca1fdb8
 
 
 
 
fecefe5
ca1fdb8
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#main.py

from fastapi import FastAPI, Form, Depends, HTTPException, status
from fastapi.requests import Request
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from auth import verify_token, oauth2_scheme, auth_views, register, UserCreate, authenticate_user, get_user_by_verification_token
from database import get_db, get_user_by_email
from datetime import timedelta
#from typing import Optional
#import auth
#import tts
import os

my_secret_key = os.environ['my_secret_key']
app = FastAPI()
#router = APIRouter()
templates = Jinja2Templates(directory="templates")

# Include the authentication router with the prefix '/auth'
#app.include_router(auth.router, prefix="")

# Include the TTS router with the prefix '/tts'
#app.include_router(tts.router, prefix="/tts")

# Dependency for verifying the user's token
def get_current_user(token: str = Depends(verify_token)):
    if not token:
        raise HTTPException(status_code=401, detail="Token not valid")
    return token
# Route for the landing page
@app.get("/", response_class=HTMLResponse)
async def landing(request: Request):
    return templates.TemplateResponse("landing.html", {"request": request})

# Your other routes and app configuration go here

@app.get("/login", response_class=HTMLResponse)
async def login(request: Request):
    return templates.TemplateResponse("login.html", {"request": request})


@app.post("/login")
async def login_post(
    request: Request,
    email: str = Form(...),
    password: str = Form(...),
    db: Session = Depends(get_db)
):
    if not email or not password:
        raise HTTPException(status_code=400, detail="Invalid email or password")

    user = authenticate_user(db, email, password)
    if user and user.is_verified:  # Check if user is verified
        access_token = auth_views.create_access_token(
            data={"sub": user.email},
            expires_delta=timedelta(minutes=auth_views.ACCESS_TOKEN_EXPIRE_MINUTES)
        )

        # Redirect the user to the protected route with the token in the URL
        url = app.url_path_for("get_protected")  # Ensure you have a name="get_protected" in your app.get("/protected") decorator
        #return RedirectResponse(url=f"/protected?token={access_token}", status_code=status.HTTP_303_SEE_OTHER)
        #return RedirectResponse(f"{url}?token={access_token}")

        response = RedirectResponse(f"{url}?token={access_token}", status_code=status.HTTP_303_SEE_OTHER)
        response.set_cookie(key="access_token", value=f"Bearer {access_token}", httponly=True)
       # response.set_cookie(key="access_token", value=access_token, httponly=True)
        return response
    elif user and not user.is_verified:  # User is not verified
        raise HTTPException(
            status_code=400,
            detail="You must verify your email before accessing this resource."
        )
    else:
        # If authentication fails, return to the login page with an error message
        return templates.TemplateResponse(
            "login.html", 
            {"request": request, "error_message": "Invalid email or password"}
        )
@app.get("/register", response_class=HTMLResponse)
async def register_get(request: Request):
    return templates.TemplateResponse("register.html", {"request": request})


@app.post("/register", response_class=HTMLResponse)
async def register_post(
    request: Request,
    username: str = Form(...),
    email: str = Form(...),
    password: str = Form(...),
    confirm_password: str = Form(...),
    db: Session = Depends(get_db)
):
    if password != confirm_password:
        # Return to the registration page with an error
        return templates.TemplateResponse("register.html", {
            "request": request,
            "error_message": "Passwords do not match."
        })

    try:
        user = UserCreate(username=username, email=email, password=password, confirm_password=confirm_password)
        register(user, db)  # If this function raises an HTTPException, it should be handled
    except HTTPException as e:
        # Return to the registration page with the error detail
        return templates.TemplateResponse("register.html", {
            "request": request,
            "error_message": e.detail
        })

    # Redirect to the successful registration page
    response = RedirectResponse("/registration_successful", status_code=status.HTTP_302_FOUND)
    return response
    
    
@app.get("/registration_successful", response_class=HTMLResponse)
async def registration_successful(request: Request):
    # Render the successful registration page
    return templates.TemplateResponse("registration_successful.html", {"request": request})


@app.get("/verify/{verification_token}", response_class=HTMLResponse)
async def verify_email(verification_token: str, db: Session = Depends(get_db)):
    user = get_user_by_verification_token(db, verification_token)
    if not user:
        raise HTTPException(status_code=400, detail="Invalid verification token")

    if user.is_verified:
        raise HTTPException(status_code=400, detail="Email already verified")

    user.is_verified = True
    user.email_verification_token = None  # Clear the verification token
    db.commit()

    # Create access token for the user after successful verification
    access_token = auth_views.create_access_token(data={"sub": user.email}, expires_delta=timedelta(minutes=auth_views.ACCESS_TOKEN_EXPIRE_MINUTES))
    # Redirect to the protected route with the token as a query parameter (or as required by your front-end/client)
    return RedirectResponse(url=f"/protected?token={access_token}")

#from jwt import decode, PyJWTError  # make sure jwt is imported

@app.get("/protected", response_class=HTMLResponse)
async def get_protected(
    request: Request, 
    token: str = Depends(verify_token),  # Use Depends to inject the token after verification
    db: Session = Depends(get_db)
):
    user_email = token  # As verify_token returns the 'sub' which is user email

    db_user = get_user_by_email(db, user_email)
    if db_user is None or not db_user.is_verified:
        raise HTTPException(status_code=401, detail="User not found or not verified in the database")

    # Render a template response
    return templates.TemplateResponse("protected.html", {"request": request, "user": db_user.username})

#@app.get("/protected", response_class=HTMLResponse)
#async def get_protected(request: Request, token: Optional[str] = None, db: Session = Depends(get_db)):
    # Try to get the token from the query parameter first, then fall back to the cookie
#    token = token or request.cookies.get("access_token")
#    if not token:
#        raise HTTPException(status_code=401, detail="Not authenticated")

#    try:
#        payload = decode(token, auth_views.SECRET_KEY, algorithms=[auth_views.ALGORITHM])
#        user_email = payload.get("sub")
#        if user_email is None:
#            raise HTTPException(status_code=401, detail="Not authenticated")
 #   except PyJWTError:
 #       raise HTTPException(status_code=401, detail="Could not validate credentials")

 #   db_user = get_user_by_email(db, user_email)
#    if db_user is None or not db_user.is_verified:
#        raise HTTPException(status_code=401, detail="User not found or not verified in the database")

#    return templates.TemplateResponse("protected.html", {"request": request, "user": db_user.username})

#async def get_protected(
 #   request: Request,
 #   token: str = Query(None),  # Accept token from query parameters
#    db: Session = Depends(get_db)
#):
    # Now pass both the request and token to the protected_route function
#    return await protected_route(request, token, db)