Skip to content

Commit 2c7b548

Browse files
Fixed broken links, added static assets, generated an emoji logo, introduced a user profile SVG, refactored utils, introduced refresh tokens
1 parent d480dfd commit 2c7b548

32 files changed

+1982
-887
lines changed

.github/dependabot.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for more information:
4+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5+
# https://containers.dev/guide/dependabot
6+
7+
version: 2
8+
updates:
9+
- package-ecosystem: "devcontainers"
10+
directory: "/"
11+
schedule:
12+
interval: weekly

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
.devcontainer
2-
.gpteng
3-
prompt
42
__pycache__
53
*.pyc
64
.env

LICENSE

Lines changed: 674 additions & 674 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This project is still under development.
44

5+
## Installation
6+
7+
`sudo apt update && sudo apt install -y python3-dev libpq-dev && pipx install poetry && poetry install && poetry shell`
8+
59
## Start development database
610

711
`docker compose up -d`

docker-compose.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ services:
22
db:
33
image: postgres:latest
44
environment:
5-
POSTGRES_USER: postgres
6-
POSTGRES_PASSWORD: postgres
7-
POSTGRES_DB: round_robin_db
5+
POSTGRES_USER: ${DB_USER}
6+
POSTGRES_PASSWORD: ${DB_PASSWORD}
7+
POSTGRES_DB: ${DB_NAME}
88
ports:
9-
- "5433:5432"
9+
- "5432:5432"
1010
volumes:
1111
- postgres_data:/var/lib/postgresql/data
1212

main.py

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import logging
22
from typing import Optional
33
from contextlib import asynccontextmanager
4-
from fastapi import FastAPI, Request, Depends
4+
from fastapi import FastAPI, Request, Depends, status
55
from fastapi.responses import RedirectResponse
66
from fastapi.staticfiles import StaticFiles
77
from fastapi.templating import Jinja2Templates
88
from sqlmodel import SQLModel, create_engine
99
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
1313

1414

1515
logger = logging.getLogger("uvicorn.error")
@@ -34,6 +34,28 @@ async def lifespan(app: FastAPI):
3434
templates = Jinja2Templates(directory="templates")
3535

3636

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+
3759
@app.exception_handler(StarletteHTTPException)
3860
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
3961
return templates.TemplateResponse(
@@ -52,23 +74,29 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE
5274
)
5375

5476

77+
# -- Unauthenticated Routes --
78+
79+
5580
@app.get("/")
5681
async def read_home(
5782
request: Request,
58-
user: Optional[User] = Depends(get_current_user),
83+
user: Optional[User] = Depends(get_optional_user),
5984
error_message: Optional[str] = None,
6085
):
6186
if user:
87+
logger.info(f"Redirecting to /dashboard for user: {user.id}")
6288
return RedirectResponse(url="/dashboard", status_code=302)
89+
logger.info("Rendering home page for unauthenticated user")
6390
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}
6593
)
6694

6795

6896
@app.get("/login")
6997
async def read_login(
7098
request: Request,
71-
user: Optional[User] = Depends(get_current_user),
99+
user: Optional[User] = Depends(get_optional_user),
72100
error_message: Optional[str] = None,
73101
):
74102
if user:
@@ -82,7 +110,7 @@ async def read_login(
82110
@app.get("/register")
83111
async def read_register(
84112
request: Request,
85-
user: Optional[User] = Depends(get_current_user),
113+
user: Optional[User] = Depends(get_optional_user),
86114
error_message: Optional[str] = None,
87115
):
88116
if user:
@@ -96,7 +124,7 @@ async def read_register(
96124
@app.get("/forgot_password")
97125
async def read_forgot_password(
98126
request: Request,
99-
user: Optional[User] = Depends(get_current_user),
127+
user: Optional[User] = Depends(get_optional_user),
100128
error_message: Optional[str] = None,
101129
):
102130
if user:
@@ -111,7 +139,7 @@ async def read_forgot_password(
111139
async def read_reset_password(
112140
request: Request,
113141
token: str,
114-
user: Optional[User] = Depends(get_current_user),
142+
user: Optional[User] = Depends(get_optional_user),
115143
error_message: Optional[str] = None,
116144
):
117145
if user:
@@ -128,71 +156,76 @@ async def read_reset_password(
128156
)
129157

130158

131-
@app.get("/dashboard")
132-
async def read_dashboard(
159+
@app.get("/about")
160+
async def read_about(
133161
request: Request,
134-
user: Optional[User] = Depends(get_current_user),
162+
user: Optional[User] = Depends(get_optional_user),
135163
error_message: Optional[str] = None,
136164
):
137-
if not user:
138-
return RedirectResponse(url="/", status_code=302)
139165
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}
142168
)
143169

144170

145-
@app.get("/user_profile")
146-
async def read_user_profile(
171+
@app.get("/privacy_policy")
172+
async def read_privacy_policy(
147173
request: Request,
148-
user: Optional[User] = Depends(get_current_user),
174+
user: Optional[User] = Depends(get_optional_user),
149175
error_message: Optional[str] = None,
150176
):
151-
if not user:
152-
return RedirectResponse(url="/", status_code=302)
153177
return templates.TemplateResponse(
154-
"user_profile/index.html",
178+
"privacy_policy.html",
155179
{"request": request, "user": user, "error_message": error_message},
156180
)
157181

158182

159-
@app.get("/about")
160-
async def read_about(
183+
@app.get("/terms_of_service")
184+
async def read_terms_of_service(
161185
request: Request,
162-
user: Optional[User] = Depends(get_current_user),
186+
user: Optional[User] = Depends(get_optional_user),
163187
error_message: Optional[str] = None,
164188
):
165189
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},
167192
)
168193

169194

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(
172200
request: Request,
173-
user: Optional[User] = Depends(get_current_user),
201+
user: User = Depends(get_authenticated_user),
174202
error_message: Optional[str] = None,
175203
):
176204
return templates.TemplateResponse(
177-
"privacy_policy.html",
205+
"dashboard/index.html",
178206
{"request": request, "user": user, "error_message": error_message},
179207
)
180208

181209

182-
@app.get("/terms_of_service")
183-
async def read_terms_of_service(
210+
@app.get("/user_profile")
211+
async def read_user_profile(
184212
request: Request,
185-
user: Optional[User] = Depends(get_current_user),
213+
user: User = Depends(get_authenticated_user),
186214
error_message: Optional[str] = None,
187215
):
188216
return templates.TemplateResponse(
189-
"terms_of_service.html",
217+
"users/profile.html",
190218
{"request": request, "user": user, "error_message": error_message},
191219
)
192220

193221

222+
# -- Include Routers --
223+
224+
194225
app.include_router(auth.router)
195226
app.include_router(organization.router)
227+
app.include_router(role.router)
228+
app.include_router(user.router)
196229

197230

198231
if __name__ == "__main__":

models.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)