Skip to content

Commit

Permalink
Merge pull request #78 from fedecarboni7/monitoring-and-ai
Browse files Browse the repository at this point in the history
Monitoring and ai
  • Loading branch information
fedecarboni7 authored Sep 9, 2024
2 parents 5cb6834 + 9dd82f8 commit 791ab6a
Show file tree
Hide file tree
Showing 12 changed files with 200 additions and 92 deletions.
59 changes: 31 additions & 28 deletions app/config/config.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,56 @@
import os
import time

from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from fastapi import Depends, FastAPI, Request
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.responses import JSONResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.middleware.sessions import SessionMiddleware

from app.config.logging_config import configure_logging, logger
from app.config.logging_config import configure_logging
from app.db.models import User
from app.utils.auth import get_current_user
from app.utils.security import verify_admin_user

templates = Jinja2Templates(directory="templates")

def create_app() -> FastAPI:
app = FastAPI(docs_url=None, redoc_url=None)

# Configuración de logging
configure_logging()

secret_key = os.getenv("SECRET_KEY")

app = FastAPI(title="Armar Equipos", docs_url=None, redoc_url=None, openapi_url=None)

app.add_middleware(SessionMiddleware, secret_key=secret_key)

app.mount("/static", StaticFiles(directory="static"), name="static")

@app.middleware("http")
async def measure_execution_time(request: Request, call_next):
ignore_paths = ["/static", "/favicon.ico", "/sm/"]

if not any(request.url.path.startswith(prefix) for prefix in ignore_paths):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
logger.debug(f"{process_time:.4f} seconds to process request: {request.method} {request.url.path}")
return response
else:
return await call_next(request)

@app.exception_handler(500)
async def internal_server_error_handler(request: Request, exc: Exception):
"""
Maneja los errores del servidor y muestra una página de error personalizada.
"""
return templates.TemplateResponse(request=request, name="500.html", status_code=500)


@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
if exc.status_code in [404, 405]: # Not Found y Method Not Allowed
return RedirectResponse(url="/")
raise exc

if exc.status_code == 500:
return templates.TemplateResponse(request=request, name="500.html", status_code=500)

return JSONResponse(
status_code=exc.status_code,
content={
"error": exc.status_code,
"detail": exc.detail
}
)

@app.get("/docs", include_in_schema=False)
async def get_documentation(current_user: User = Depends(get_current_user)):
verify_admin_user(current_user, detail="Unauthorized: /docs")
return get_swagger_ui_html(openapi_url="/openapi.json", title="docs")

@app.get("/openapi.json", include_in_schema=False)
async def openapi(current_user: User = Depends(get_current_user)):
verify_admin_user(current_user, detail="Unauthorized: /openapi.json")
return app.openapi()

return app
13 changes: 6 additions & 7 deletions app/db/database.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import os

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import sessionmaker

from app.config.logging_config import logger

LOCAL_DB = os.getenv("LOCAL_DB", "").lower() == "true"

class Base(DeclarativeBase):
pass

if LOCAL_DB:
logger.info("Using local database")
dbUrl = "sqlite:///./test.db"
engine = create_engine(dbUrl, connect_args={'check_same_thread': False})
Base.metadata.create_all(engine)
else:
TURSO_DATABASE_URL = os.getenv("TURSO_DATABASE_URL")
TURSO_AUTH_TOKEN = os.getenv("TURSO_AUTH_TOKEN")
Expand All @@ -21,12 +26,6 @@

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

# Create all tables in the database
if LOCAL_DB:
Base.metadata.create_all(engine)

def get_db():
db = SessionLocal()
try:
Expand Down
4 changes: 2 additions & 2 deletions app/db/database_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ def query_user(db: Session, username: str):
def query_players(db: Session, current_user_id: int):
return db.query(Player).filter(Player.user_id == current_user_id).all()

def query_player(db: Session, player_id: int):
return db.query(Player).filter(Player.id == player_id).first()
def query_player(db: Session, player_id: int, current_user_id: int):
return db.query(Player).filter(Player.id == player_id and Player.user_id == current_user_id).first()
4 changes: 2 additions & 2 deletions app/db/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from passlib.hash import pbkdf2_sha256
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
from sqlalchemy.orm import relationship

from app.db.database import Base
Expand Down Expand Up @@ -35,4 +35,4 @@ class Player(Base):
fuerza_cuerpo = Column(Integer)
vision = Column(Integer)
user_id = Column(Integer, ForeignKey("users.id"))
user = relationship("User", back_populates="players")
user = relationship("User", back_populates="players")
6 changes: 3 additions & 3 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@

app = create_app()

app.include_router(player_router)
app.include_router(auth_router)
app.include_router(main_router)
app.include_router(player_router, tags=["player"])
app.include_router(auth_router, tags=["auth"])
app.include_router(main_router, tags=["main"])
45 changes: 40 additions & 5 deletions app/routes/auth_routes.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
from fastapi import APIRouter, Depends, Form, Request
from datetime import timedelta
from typing import Annotated
from fastapi import APIRouter, Depends, Form, HTTPException, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.security import OAuth2PasswordRequestForm
from pydantic import BaseModel
from sqlalchemy.orm import Session
from sqlalchemy.exc import OperationalError

from app.config.config import templates
from app.db.database import get_db
from app.db.database_utils import execute_with_retries, query_user
from app.db.models import User
from app.utils.security import create_access_token
from app.utils.validators import validate_password, validate_username


router = APIRouter()

@router.get("/signup", response_class=HTMLResponse)
@router.get("/signup", response_class=HTMLResponse, include_in_schema=False)
async def signup_page(request: Request):
if request.session.get("user_id"):
return RedirectResponse(url="/", status_code=302)
Expand All @@ -24,7 +29,7 @@ async def signup(
request: Request,
username: str = Form(...),
password: str = Form(...),
db: Session = Depends(get_db),
db: Session = Depends(get_db)
):
username = username.strip().lower()

Expand Down Expand Up @@ -52,8 +57,11 @@ async def signup(
return RedirectResponse(url="/", status_code=302)


@router.get("/login", response_class=HTMLResponse)
@router.get("/login", response_class=HTMLResponse, include_in_schema=False)
async def login_page(request: Request):
referer = request.headers.get("referer")
if referer and 'logout' in referer:
request.session.clear()
if request.session.get("user_id"):
return RedirectResponse(url="/", status_code=302)
return templates.TemplateResponse(request=request, name="login.html")
Expand Down Expand Up @@ -82,4 +90,31 @@ async def login(
@router.get("/logout")
async def logout(request: Request):
request.session.clear()
return RedirectResponse("/login", status_code=307)
return RedirectResponse("/login", status_code=307)

class Token(BaseModel):
access_token: str
token_type: str

@router.post("/token", response_model=Token)
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
db: Session = Depends(get_db)
) -> Token:

user = db.query(User).filter(User.username == form_data.username).first()

if not user or not user.verify_password(form_data.password):
raise HTTPException(
status_code=401,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)

access_token_expires = timedelta(minutes=15)

access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)

return Token(access_token=access_token, token_type="bearer")
33 changes: 12 additions & 21 deletions app/routes/main_routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import time
from typing import Dict, List

from fastapi import APIRouter, Depends, Request
Expand All @@ -7,7 +6,6 @@
from requests import Session

from app.config.config import templates
from app.config.logging_config import logger
from app.db.database import get_db
from app.db.database_utils import execute_with_retries, query_players
from app.db.models import Player, User
Expand All @@ -18,18 +16,18 @@

router = APIRouter()

@router.get("/landing-page", response_class=HTMLResponse)
@router.get("/landing-page", response_class=HTMLResponse, include_in_schema=False)
async def landing_page(request: Request):
return templates.TemplateResponse(request=request, name="landing-page.html")

calculated_results: Dict[str, dict] = {}

@router.get("/", response_class=HTMLResponse)
@router.get("/", response_class=HTMLResponse, include_in_schema=False)
async def get_form(
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
if not current_user:
request.session.clear()
return RedirectResponse("/landing-page", status_code=302)
Expand All @@ -53,13 +51,16 @@ async def get_form(
return templates.TemplateResponse(request=request, name="index.html", context=context)


@router.post("/submit", response_class=HTMLResponse)
async def submit_form(request: Request, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
@router.post("/submit", response_class=HTMLResponse, include_in_schema=False)
async def submit_form(
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
if not current_user:
request.session.clear()
return RedirectResponse("/landing-page", status_code=302)

start_time_1 = time.time()
current_user_id = current_user.id
form_data = await request.form()
list_players = form_data._list
Expand Down Expand Up @@ -109,10 +110,6 @@ async def submit_form(request: Request, db: Session = Depends(get_db), current_u

db.commit()

process_time_1 = time.time() - start_time_1
logger.debug(f"{process_time_1:.4f} seconds to save or update players in the database")
start_time_2 = time.time()

# Calcular equipos
player_names = [p.name for p in player_data]
player_scores = [
Expand All @@ -136,10 +133,6 @@ async def submit_form(request: Request, db: Session = Depends(get_db), current_u
for equipos in mejores_equipos:
teams.append([[player_names[i] for i in list(equipos[0])]])
teams.append([[player_names[i] for i in list(equipos[1])]])

process_time_2 = time.time() - start_time_2
logger.debug(f"{process_time_2:.4f} seconds to calculate the best teams")
start_time_3 = time.time()

# Calculate the total and average skills for each team
try:
Expand Down Expand Up @@ -198,6 +191,4 @@ async def submit_form(request: Request, db: Session = Depends(get_db), current_u
"playerDataDict": player_data_dict
}

process_time_3 = time.time() - start_time_3
logger.debug(f"{process_time_3:.4f} seconds to calculate the total skills of each team and return the results")
return RedirectResponse(url="/", status_code=303)
Loading

0 comments on commit 791ab6a

Please sign in to comment.