1
1
import logging
2
2
from typing import Optional
3
3
from contextlib import asynccontextmanager
4
- from fastapi import FastAPI , Request , Depends
4
+ from fastapi import FastAPI , Request , Depends , status
5
5
from fastapi .responses import RedirectResponse
6
6
from fastapi .staticfiles import StaticFiles
7
7
from fastapi .templating import Jinja2Templates
8
8
from sqlmodel import SQLModel , create_engine
9
9
from fastapi .exceptions import RequestValidationError , StarletteHTTPException
10
- from routers import auth , organization , score , template , version
11
- from utils import get_current_user , get_connection_url
12
- from models import User
10
+ from routers import auth , organization , role , user
11
+ from utils . auth import get_authenticated_user , get_optional_user , NeedsNewTokens
12
+ from utils . db import User , get_connection_url
13
13
14
14
15
15
logger = logging .getLogger ("uvicorn.error" )
@@ -34,6 +34,28 @@ async def lifespan(app: FastAPI):
34
34
templates = Jinja2Templates (directory = "templates" )
35
35
36
36
37
+ # Middleware to handle the NeedsNewTokens exception
38
+ @app .exception_handler (NeedsNewTokens )
39
+ async def needs_new_tokens_handler (request : Request , exc : NeedsNewTokens ):
40
+ response = RedirectResponse (
41
+ url = request .url .path , status_code = status .HTTP_307_TEMPORARY_REDIRECT )
42
+ response .set_cookie (
43
+ key = "access_token" ,
44
+ value = exc .access_token ,
45
+ httponly = True ,
46
+ secure = True ,
47
+ samesite = "strict"
48
+ )
49
+ response .set_cookie (
50
+ key = "refresh_token" ,
51
+ value = exc .refresh_token ,
52
+ httponly = True ,
53
+ secure = True ,
54
+ samesite = "strict"
55
+ )
56
+ return response
57
+
58
+
37
59
@app .exception_handler (StarletteHTTPException )
38
60
async def http_exception_handler (request : Request , exc : StarletteHTTPException ):
39
61
return templates .TemplateResponse (
@@ -52,23 +74,29 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE
52
74
)
53
75
54
76
77
+ # -- Unauthenticated Routes --
78
+
79
+
55
80
@app .get ("/" )
56
81
async def read_home (
57
82
request : Request ,
58
- user : Optional [User ] = Depends (get_current_user ),
83
+ user : Optional [User ] = Depends (get_optional_user ),
59
84
error_message : Optional [str ] = None ,
60
85
):
61
86
if user :
87
+ logger .info (f"Redirecting to /dashboard for user: { user .id } " )
62
88
return RedirectResponse (url = "/dashboard" , status_code = 302 )
89
+ logger .info ("Rendering home page for unauthenticated user" )
63
90
return templates .TemplateResponse (
64
- "index.html" , {"request" : request , "user" : user , "error_message" : error_message }
91
+ "index.html" , {"request" : request , "user" : user ,
92
+ "error_message" : error_message }
65
93
)
66
94
67
95
68
96
@app .get ("/login" )
69
97
async def read_login (
70
98
request : Request ,
71
- user : Optional [User ] = Depends (get_current_user ),
99
+ user : Optional [User ] = Depends (get_optional_user ),
72
100
error_message : Optional [str ] = None ,
73
101
):
74
102
if user :
@@ -82,7 +110,7 @@ async def read_login(
82
110
@app .get ("/register" )
83
111
async def read_register (
84
112
request : Request ,
85
- user : Optional [User ] = Depends (get_current_user ),
113
+ user : Optional [User ] = Depends (get_optional_user ),
86
114
error_message : Optional [str ] = None ,
87
115
):
88
116
if user :
@@ -96,7 +124,7 @@ async def read_register(
96
124
@app .get ("/forgot_password" )
97
125
async def read_forgot_password (
98
126
request : Request ,
99
- user : Optional [User ] = Depends (get_current_user ),
127
+ user : Optional [User ] = Depends (get_optional_user ),
100
128
error_message : Optional [str ] = None ,
101
129
):
102
130
if user :
@@ -111,7 +139,7 @@ async def read_forgot_password(
111
139
async def read_reset_password (
112
140
request : Request ,
113
141
token : str ,
114
- user : Optional [User ] = Depends (get_current_user ),
142
+ user : Optional [User ] = Depends (get_optional_user ),
115
143
error_message : Optional [str ] = None ,
116
144
):
117
145
if user :
@@ -128,71 +156,76 @@ async def read_reset_password(
128
156
)
129
157
130
158
131
- @app .get ("/dashboard " )
132
- async def read_dashboard (
159
+ @app .get ("/about " )
160
+ async def read_about (
133
161
request : Request ,
134
- user : Optional [User ] = Depends (get_current_user ),
162
+ user : Optional [User ] = Depends (get_optional_user ),
135
163
error_message : Optional [str ] = None ,
136
164
):
137
- if not user :
138
- return RedirectResponse (url = "/" , status_code = 302 )
139
165
return templates .TemplateResponse (
140
- "dashboard/index .html" ,
141
- {"request" : request , "user" : user , "error_message" : error_message },
166
+ "about .html" ,
167
+ {"request" : request , "user" : user , "error_message" : error_message }
142
168
)
143
169
144
170
145
- @app .get ("/user_profile " )
146
- async def read_user_profile (
171
+ @app .get ("/privacy_policy " )
172
+ async def read_privacy_policy (
147
173
request : Request ,
148
- user : Optional [User ] = Depends (get_current_user ),
174
+ user : Optional [User ] = Depends (get_optional_user ),
149
175
error_message : Optional [str ] = None ,
150
176
):
151
- if not user :
152
- return RedirectResponse (url = "/" , status_code = 302 )
153
177
return templates .TemplateResponse (
154
- "user_profile/index .html" ,
178
+ "privacy_policy .html" ,
155
179
{"request" : request , "user" : user , "error_message" : error_message },
156
180
)
157
181
158
182
159
- @app .get ("/about " )
160
- async def read_about (
183
+ @app .get ("/terms_of_service " )
184
+ async def read_terms_of_service (
161
185
request : Request ,
162
- user : Optional [User ] = Depends (get_current_user ),
186
+ user : Optional [User ] = Depends (get_optional_user ),
163
187
error_message : Optional [str ] = None ,
164
188
):
165
189
return templates .TemplateResponse (
166
- "about.html" , {"request" : request , "user" : user , "error_message" : error_message }
190
+ "terms_of_service.html" ,
191
+ {"request" : request , "user" : user , "error_message" : error_message },
167
192
)
168
193
169
194
170
- @app .get ("/privacy_policy" )
171
- async def read_privacy_policy (
195
+ # -- Authenticated Routes --
196
+
197
+
198
+ @app .get ("/dashboard" )
199
+ async def read_dashboard (
172
200
request : Request ,
173
- user : Optional [ User ] = Depends (get_current_user ),
201
+ user : User = Depends (get_authenticated_user ),
174
202
error_message : Optional [str ] = None ,
175
203
):
176
204
return templates .TemplateResponse (
177
- "privacy_policy .html" ,
205
+ "dashboard/index .html" ,
178
206
{"request" : request , "user" : user , "error_message" : error_message },
179
207
)
180
208
181
209
182
- @app .get ("/terms_of_service " )
183
- async def read_terms_of_service (
210
+ @app .get ("/user_profile " )
211
+ async def read_user_profile (
184
212
request : Request ,
185
- user : Optional [ User ] = Depends (get_current_user ),
213
+ user : User = Depends (get_authenticated_user ),
186
214
error_message : Optional [str ] = None ,
187
215
):
188
216
return templates .TemplateResponse (
189
- "terms_of_service .html" ,
217
+ "users/profile .html" ,
190
218
{"request" : request , "user" : user , "error_message" : error_message },
191
219
)
192
220
193
221
222
+ # -- Include Routers --
223
+
224
+
194
225
app .include_router (auth .router )
195
226
app .include_router (organization .router )
227
+ app .include_router (role .router )
228
+ app .include_router (user .router )
196
229
197
230
198
231
if __name__ == "__main__" :
0 commit comments