mirror of
https://github.com/marcogll/telegram_new_socias.git
synced 2026-01-13 13:15:16 +00:00
feat: Enhance database connection robustness, update onboarding command to /welcome, and remove /socia_finder functionality.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
|||||||
# Environments
|
# Environments
|
||||||
.env
|
.env
|
||||||
|
.env.bak
|
||||||
|
.venv/
|
||||||
venv/
|
venv/
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
|||||||
3
main.py
3
main.py
@@ -30,8 +30,7 @@ async def menu_principal(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
"📝 `/welcome` - Iniciar onboarding/contrato\n"
|
"📝 `/welcome` - Iniciar onboarding/contrato\n"
|
||||||
"🖨️ `/print` - Imprimir o enviar archivo\n"
|
"🖨️ `/print` - Imprimir o enviar archivo\n"
|
||||||
"🌴 `/vacaciones` - Solicitar días libres\n"
|
"🌴 `/vacaciones` - Solicitar días libres\n"
|
||||||
"⏱️ `/permiso` - Solicitar permiso por horas\n"
|
"⏱️ `/permiso` - Solicitar permiso por horas\n\n"
|
||||||
"🔍 `/socia_finder` - Buscar datos de una compañera\n\n"
|
|
||||||
"Selecciona un comando para empezar."
|
"Selecciona un comando para empezar."
|
||||||
)
|
)
|
||||||
await update.message.reply_text(texto)
|
await update.message.reply_text(texto)
|
||||||
|
|||||||
@@ -1,28 +1,12 @@
|
|||||||
import os
|
|
||||||
from sqlalchemy import create_engine, Column, Integer, String, DateTime, MetaData, Table
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
from datetime import datetime
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import Column, DateTime, Integer, MetaData, String, create_engine
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
# Configuración de logging
|
# Configuración de logging
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||||
|
|
||||||
# Construir la URL de la base de datos desde las variables de entorno individuales
|
|
||||||
try:
|
|
||||||
user = os.getenv("MYSQL_USER")
|
|
||||||
password = os.getenv("MYSQL_PASSWORD")
|
|
||||||
host = "db" # El nombre del servicio de la base de datos en docker-compose
|
|
||||||
database = os.getenv("MYSQL_DATABASE")
|
|
||||||
DATABASE_URL = f"mysql+mysqlconnector://{user}:{password}@{host}:3306/{database}"
|
|
||||||
|
|
||||||
# Crear el motor de la base de datos
|
|
||||||
engine = create_engine(DATABASE_URL)
|
|
||||||
metadata = MetaData()
|
|
||||||
|
|
||||||
except AttributeError:
|
|
||||||
logging.error("Error: Faltan una o más variables de entorno para la base de datos (MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE).")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Base para los modelos declarativos
|
# Base para los modelos declarativos
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
@@ -37,21 +21,47 @@ class RequestLog(Base):
|
|||||||
message = Column(String(500))
|
message = Column(String(500))
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
created_at = Column(DateTime, default=datetime.utcnow)
|
||||||
|
|
||||||
|
def _build_engine():
|
||||||
|
"""Crea un engine de SQLAlchemy si hay variables de entorno suficientes."""
|
||||||
|
user = os.getenv("MYSQL_USER")
|
||||||
|
password = os.getenv("MYSQL_PASSWORD")
|
||||||
|
database = os.getenv("MYSQL_DATABASE")
|
||||||
|
host = os.getenv("MYSQL_HOST") or "db" # Permitimos override para uso local
|
||||||
|
|
||||||
|
if not all([user, password, database]):
|
||||||
|
logging.warning("DB logging deshabilitado: faltan MYSQL_USER/MYSQL_PASSWORD/MYSQL_DATABASE.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
db_url = f"mysql+mysqlconnector://{user}:{password}@{host}:3306/{database}"
|
||||||
|
return create_engine(db_url, pool_pre_ping=True)
|
||||||
|
except Exception as exc:
|
||||||
|
logging.error(f"No se pudo crear el engine de base de datos: {exc}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Crear el engine y sesión si es posible
|
||||||
|
engine = _build_engine()
|
||||||
|
metadata = MetaData() if engine else None
|
||||||
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) if engine else None
|
||||||
|
|
||||||
# Función para inicializar la base de datos
|
# Función para inicializar la base de datos
|
||||||
def init_db():
|
def init_db():
|
||||||
|
if not engine:
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
logging.info("Inicializando la base de datos y creando tablas si no existen...")
|
logging.info("Inicializando la base de datos y creando tablas si no existen...")
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
logging.info("Tablas verificadas/creadas correctamente.")
|
logging.info("Tablas verificadas/creadas correctamente.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error al inicializar la base de datos: {e}")
|
logging.error(f"Error al inicializar la base de datos: {e}")
|
||||||
raise
|
# No propagamos para que el bot pueda seguir levantando aunque no haya DB
|
||||||
|
|
||||||
# Crear una sesión para interactuar con la base de datos
|
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
||||||
|
|
||||||
# Función para registrar una solicitud en la base de datos
|
# Función para registrar una solicitud en la base de datos
|
||||||
def log_request(telegram_id, username, command, message):
|
def log_request(telegram_id, username, command, message):
|
||||||
|
if not SessionLocal:
|
||||||
|
logging.debug("Log de DB omitido (DB no configurada).")
|
||||||
|
return
|
||||||
|
|
||||||
db_session = SessionLocal()
|
db_session = SessionLocal()
|
||||||
try:
|
try:
|
||||||
log_entry = RequestLog(
|
log_entry = RequestLog(
|
||||||
|
|||||||
@@ -321,12 +321,25 @@ async def cancelar(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
|||||||
context.user_data.clear()
|
context.user_data.clear()
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
|
## Definición de estados para el ConversationHandler
|
||||||
|
states = {}
|
||||||
|
for i in range(34):
|
||||||
|
callback = partial(manejar_flujo, estado_actual=i)
|
||||||
|
states[i] = [MessageHandler(filters.TEXT & ~filters.COMMAND, callback)]
|
||||||
|
|
||||||
|
states[34] = [MessageHandler(filters.TEXT & ~filters.COMMAND, finalizar)]
|
||||||
|
|
||||||
|
# Handler listo para importar en main.py
|
||||||
|
onboarding_handler = ConversationHandler(
|
||||||
|
entry_points=[CommandHandler("welcome", start)], # Cambiado a /welcome
|
||||||
|
states=states, # Tu diccionario de estados
|
||||||
|
fallbacks=[CommandHandler("cancelar", cancelar)]
|
||||||
|
)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
defaults = Defaults(parse_mode=ParseMode.MARKDOWN)
|
defaults = Defaults(parse_mode=ParseMode.MARKDOWN)
|
||||||
application = Application.builder().token(TOKEN).defaults(defaults).build()
|
application = Application.builder().token(TOKEN).defaults(defaults).build()
|
||||||
|
|
||||||
# states definition moved to global scope
|
|
||||||
|
|
||||||
conv_handler = ConversationHandler(
|
conv_handler = ConversationHandler(
|
||||||
entry_points=[CommandHandler("contrato", start)],
|
entry_points=[CommandHandler("contrato", start)],
|
||||||
states=states,
|
states=states,
|
||||||
@@ -339,19 +352,3 @@ def main():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
# ... todo el código del contrato ...
|
|
||||||
|
|
||||||
# Definición de estados para el ConversationHandler
|
|
||||||
states = {}
|
|
||||||
for i in range(34):
|
|
||||||
callback = partial(manejar_flujo, estado_actual=i)
|
|
||||||
states[i] = [MessageHandler(filters.TEXT & ~filters.COMMAND, callback)]
|
|
||||||
|
|
||||||
states[34] = [MessageHandler(filters.TEXT & ~filters.COMMAND, finalizar)]
|
|
||||||
|
|
||||||
# Al final:
|
|
||||||
onboarding_handler = ConversationHandler(
|
|
||||||
entry_points=[CommandHandler("welcome", start)], # Cambiado a /welcome
|
|
||||||
states=states, # Tu diccionario de estados
|
|
||||||
fallbacks=[CommandHandler("cancelar", cancelar)]
|
|
||||||
)
|
|
||||||
@@ -64,8 +64,8 @@ async def recibir_archivo(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
|||||||
msg.attach(attachment)
|
msg.attach(attachment)
|
||||||
|
|
||||||
# 3. Enviar el correo
|
# 3. Enviar el correo
|
||||||
context = ssl.create_default_context()
|
ssl_context = ssl.create_default_context()
|
||||||
with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=context) as server:
|
with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=ssl_context) as server:
|
||||||
server.login(SMTP_USER, SMTP_PASSWORD)
|
server.login(SMTP_USER, SMTP_PASSWORD)
|
||||||
server.sendmail(SMTP_USER, SMTP_RECIPIENT, msg.as_string())
|
server.sendmail(SMTP_USER, SMTP_RECIPIENT, msg.as_string())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user