Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #38

Merged
merged 11 commits into from
Aug 8, 2024
7 changes: 6 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## TO-DO
# TO-DO

## Prioriratias
- **Hacer refactor de código para mejorar la legibilidad y eficiencia**
- **Implementar validación de entrada de datos para prevenir inyección SQL**

## A futuro
- **Agregar una opción para compartir datos de jugadores con otros usuarios**
- **Permitir la selección de habilidades específicas para la comparación**
- **Limitar la cantidad de opciones de equipos a 3 para optimizar la eficiencia**
Expand Down
Empty file added app/config/__init__.py
Empty file.
29 changes: 29 additions & 0 deletions app/config/logging_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import logging
import os

import colorlog

# Configuración del colorlog
handler = colorlog.StreamHandler()
formatter = colorlog.ColoredFormatter(
'%(log_color)s%(levelname)s%(white)s: %(message)s',
log_colors={
'DEBUG': 'cyan',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bg_white',
}
)
handler.setFormatter(formatter)

# Configuración básica del logging
logger = logging.getLogger()
logging_level = os.getenv('LOGGING_LEVEL', 'INFO').upper()

try:
logger.setLevel(getattr(logging, logging_level))
except AttributeError:
logger.setLevel(logging.INFO)

logger.addHandler(handler)
8 changes: 4 additions & 4 deletions app/database.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import os

from passlib.hash import pbkdf2_sha256

from sqlalchemy import ForeignKey, create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, relationship, declarative_base

from app.config.logging_config import logger

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

if LOCAL_DB:
logger.info("Using local database")
dbUrl = "sqlite:///./test.db"
engine = create_engine(dbUrl, connect_args={'check_same_thread': False})
else:
TURSO_DATABASE_URL = os.getenv("TURSO_DATABASE_URL")
TURSO_AUTH_TOKEN = os.getenv("TURSO_AUTH_TOKEN")
timeout = int(os.getenv('DB_TIMEOUT', 30))
pool_size = int(os.getenv("POOL_SIZE", 5))
pool_recycle = int(os.getenv("POOL_RECYCLE", 1800))

dbUrl = f"sqlite+{TURSO_DATABASE_URL}/?authToken={TURSO_AUTH_TOKEN}&secure=true"
engine = create_engine(dbUrl, connect_args={'check_same_thread': False, 'timeout': timeout}, pool_size=pool_size, pool_recycle=pool_recycle)
engine = create_engine(dbUrl, connect_args={'check_same_thread': False, 'timeout': timeout}, pool_pre_ping=True)

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

Expand Down
30 changes: 17 additions & 13 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import logging
import os
import time
from typing import Dict, List

from fastapi import FastAPI, Form, Request, Depends, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles

from starlette.middleware.sessions import SessionMiddleware
from starlette.exceptions import HTTPException as StarletteHTTPException

from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.middleware.sessions import SessionMiddleware
from typing import Dict, List

from app.auth import get_current_user
from app.config.logging_config import logger
from app.database import User, get_db, Player
from app.schemas import PlayerCreate
from app.team_optimizer import find_best_combination
Expand All @@ -32,9 +31,6 @@
logging.getLogger('libsql_client.dbapi2._sync_executor').setLevel(logging.WARNING)
logging.getLogger('libsql_client.dbapi2.types').setLevel(logging.WARNING)

# Configuración general de logging (opcional)
logging.basicConfig(level=logging.INFO)

@app.middleware("http")
async def measure_execution_time(request: Request, call_next):
ignore_paths = ["/static", "/favicon.ico", "/sm/"]
Expand All @@ -43,12 +39,20 @@ async def measure_execution_time(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
logging.info(f" {process_time:.4f} seconds to process request: {request.method} {request.url.path}")
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("500.html", {"request": request}, 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
Expand Down Expand Up @@ -189,7 +193,7 @@ async def submit_form(request: Request, db: Session = Depends(get_db), current_u
db.commit()

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

# Calcular equipos
Expand Down Expand Up @@ -217,7 +221,7 @@ async def submit_form(request: Request, db: Session = Depends(get_db), current_u
teams.append([[player_names[i] for i in list(equipos[1])]])

process_time_2 = time.time() - start_time_2
logging.info(f" {process_time_2:.4f} seconds to calculate the best teams")
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
Expand Down Expand Up @@ -258,7 +262,7 @@ async def submit_form(request: Request, db: Session = Depends(get_db), current_u
}

process_time_3 = time.time() - start_time_3
logging.info(f" {process_time_3:.4f} seconds to calculate the total skills of each team and return the results")
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)


Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ pytest==8.2.2
SQLAlchemy==2.0.31
starlette==0.37.2
itsdangerous
sqlalchemy-libsql
sqlalchemy-libsql
colorlog
42 changes: 34 additions & 8 deletions static/css/style.css → static/css/styles-v1.0.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
html, body {
height: 100%;
}

body {
background-color: #1c1c1c;
color: #e0e0e0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
min-height: 100vh;
}

.content {
flex: 1;
}

h1 {
Expand Down Expand Up @@ -346,18 +357,31 @@ tr:last-child {
right: 20px;
background-color: #333333d0;
color: white;
padding: 10px 10px;
padding: 10px;
border-radius: 5px;
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.3);
font-size: 16px;
cursor: pointer;
display: inline-block;
}

.badge {
position: absolute;
top: -6px;
right: -5px;
background-color: #444;
color: #e0e0e0;
border-radius: 50%;
padding: 2px 5px;
font-size: 12px;
line-height: 1;
display: inline-block;
}

#selected-players-list {
display: none;
position: absolute;
bottom: 50px;
right: 0;
right: -10px;
background-color: transparent;
color: #fff;
padding: 10px;
Expand Down Expand Up @@ -403,8 +427,8 @@ tr:last-child {

#scroll-button {
position: fixed;
bottom: 18px;
right: 164px;
bottom: 20px;
right: 65px;
background-color: transparent;
padding: 0;
font-size: 24px;
Expand Down Expand Up @@ -476,13 +500,15 @@ tr:last-child {
.footer-links {
display: flex;
justify-content: center;
gap: 10px;
gap: 20px;
margin-top: 10px;
}

.footer-link {
color: #e0e0e0;
text-decoration: none;
font-weight: 500;
padding: 5px;
}

.footer {
padding: 10px 0;
}
Binary file added static/favicon-v1.0/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/favicon-v1.0/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/favicon-v1.0/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/favicon-v1.0/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/favicon-v1.0/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/favicon-v1.0/favicon.ico
Binary file not shown.
File renamed without changes.
Binary file removed static/favicon/android-chrome-192x192.png
Binary file not shown.
Binary file removed static/favicon/android-chrome-512x512.png
Binary file not shown.
Binary file removed static/favicon/apple-touch-icon.png
Binary file not shown.
Binary file removed static/favicon/favicon-16x16.png
Binary file not shown.
Binary file removed static/favicon/favicon-32x32.png
Binary file not shown.
Binary file removed static/favicon/favicon.ico
Binary file not shown.
File renamed without changes.
81 changes: 81 additions & 0 deletions templates/500.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error 500 - Error del servidor</title>
<link rel="apple-touch-icon" sizes="180x180" href="../static/favicon-v1.0/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../static/favicon-v1.0/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../static/favicon-v1.0/favicon-16x16.png">
<link rel="manifest" href="../static/favicon-v1.0/site.webmanifest">
<style>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f8d7da;
color: #721c24;
font-family: Arial, sans-serif;
}
.container {
text-align: center;
}
.countdown {
font-size: 1rem;
font-weight: bold;
margin-top: 10px;
}
.icon {
font-size: 3rem;
margin-bottom: 10px;
}
.message {
margin-top: 20px;
font-size: 1.2rem;
}
.contact-button {
margin-top: 10px;
padding: 10px 20px;
font-size: 1rem;
color: #ffffff;
background-color: #721c24;
border: none;
border-radius: 5px;
cursor: pointer;
}
.contact-button:hover {
background-color: #d3d3d3;
color: #721c24;
}
</style>
</head>
<body>
<div class="container">
<h1>500 - Error del servidor</h1>
<p>Lo sentimos, tuvimos un problema en el servidor.</p>
<p>Serás redirigido al login en <span id="countdown" class="countdown">10</span> segundos...</p>
<p class="message">Si sigues teniendo este problema, por favor comunícate con el creador del sitio.</p>
<a href="mailto:fedecarboni7@gmail.com" class="contact-button">Enviar email</a>
</div>
<script>
let countdownElement = document.getElementById('countdown');
let timeLeft = 10; // Tiempo en segundos

function updateCountdown() {
countdownElement.textContent = timeLeft;
if (timeLeft <= 0) {
window.location.href = '/login';
} else {
timeLeft--;
setTimeout(updateCountdown, 1000); // Actualiza cada segundo
}
}

// Inicia el contador
updateCountdown();
</script>
</body>
</html>
34 changes: 18 additions & 16 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Armar Equipos</title>
<link rel="apple-touch-icon" sizes="180x180" href="../static/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../static/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../static/favicon/favicon-16x16.png">
<link rel="manifest" href="../static/favicon/site.webmanifest">
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
<link rel="apple-touch-icon" sizes="180x180" href="../static/favicon-v1.0/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../static/favicon-v1.0/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../static/favicon-v1.0/favicon-16x16.png">
<link rel="manifest" href="../static/favicon-v1.0/site.webmanifest">
<link rel="stylesheet" type="text/css" href="/static/css/styles-v1.0.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css">
<script src="static/js/script.js"></script>
<script src="static/js/script-v1.0.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div class="content">
<h1>Armar Equipos</h1>

<div class="search-container">
Expand Down Expand Up @@ -221,7 +222,8 @@ <h2>Equipo 2</h2>
{% endif %}

<div id="floating-button">
Seleccionados: <span id="selected-count">0</span>
<i class="fa-solid fa-list-check" style="font-size: 20px;"></i>
<span id="selected-count" class="badge">0</span>
<div id="selected-players-list" class="hidden">
<ul id="selected-players-ul"></ul>
</div>
Expand All @@ -230,14 +232,14 @@ <h2>Equipo 2</h2>
<button type="button" id="scroll-button" onclick="scrollToSubmit()">
<i class="fa-solid fa-circle-down"></i>
</button>

</body>
<footer>
<div class="footer-links">
<a class="footer-link" href="mailto:fedecarboni7@gmail.com"><i class="fa-regular fa-comment"></i></a>
<a class="footer-link" href="https://www.linkedin.com/in/federicocarboni7/" target="_blank"><i class="fa-brands fa-linkedin"></i></a>
<a class="footer-link" href="https://github.com/fedecarboni7" target="_blank"><i class="fa-brands fa-github"></i></a>
</div>
<p class="copyright">© 2024 fedecarboni7</p>
</footer>
<footer class="footer">
<div class="footer-links">
<a class="footer-link" href="mailto:fedecarboni7@gmail.com"><i class="fa-regular fa-comment"></i></a>
<a class="footer-link" href="https://www.linkedin.com/in/federicocarboni7/" target="_blank"><i class="fa-brands fa-linkedin"></i></a>
<a class="footer-link" href="https://github.com/fedecarboni7" target="_blank"><i class="fa-brands fa-github"></i></a>
</div>
<p class="copyright">© 2024 fedecarboni7</p>
</footer>
</body>
</html>
Loading
Loading