Corrección importación CSV, robustez en restore_feeds y scripts de instalación para PostgreSQL
This commit is contained in:
parent
72dd972352
commit
0442d3fc0e
6 changed files with 119 additions and 68 deletions
54
app.py
54
app.py
|
|
@ -1,11 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Flask RSS aggregator — versión PostgreSQL
|
||||
|
||||
Cambios principales respecto al original (MySQL):
|
||||
- mysql.connector → psycopg2
|
||||
- DB_CONFIG con claves PostgreSQL
|
||||
- Función auxiliar get_conn() para abrir conexiones
|
||||
- Reemplazo de INSERT IGNORE / ON DUPLICATE KEY UPDATE por ON CONFLICT
|
||||
(Copyright tuyo 😉, soporte robusto de importación desde CSV)
|
||||
"""
|
||||
|
||||
from flask import Flask, render_template, request, redirect, url_for, Response
|
||||
|
|
@ -32,12 +28,10 @@ DB_CONFIG = {
|
|||
"password": "x",
|
||||
}
|
||||
|
||||
|
||||
def get_conn():
|
||||
"""Devuelve una conexión nueva usando psycopg2 y el diccionario DB_CONFIG."""
|
||||
return psycopg2.connect(**DB_CONFIG)
|
||||
|
||||
|
||||
MAX_FALLOS = 5 # Número máximo de fallos antes de desactivar el feed
|
||||
|
||||
# ======================================
|
||||
|
|
@ -109,7 +103,6 @@ def home():
|
|||
pais_id=int(pais_id) if pais_id else None,
|
||||
)
|
||||
|
||||
|
||||
# ======================================
|
||||
# Gestión de feeds en /feeds
|
||||
# ======================================
|
||||
|
|
@ -152,7 +145,6 @@ def feeds():
|
|||
paises=paises,
|
||||
)
|
||||
|
||||
|
||||
# Añadir feed
|
||||
@app.route("/add", methods=["POST"])
|
||||
def add_feed():
|
||||
|
|
@ -180,7 +172,6 @@ def add_feed():
|
|||
conn.close()
|
||||
return redirect(url_for("feeds"))
|
||||
|
||||
|
||||
# Editar feed
|
||||
@app.route("/edit/<int:feed_id>", methods=["GET", "POST"])
|
||||
def edit_feed(feed_id):
|
||||
|
|
@ -230,7 +221,6 @@ def edit_feed(feed_id):
|
|||
conn.close()
|
||||
return render_template("edit_feed.html", feed=feed, categorias=categorias, paises=paises)
|
||||
|
||||
|
||||
# Eliminar feed
|
||||
@app.route("/delete/<int:feed_id>")
|
||||
def delete_feed(feed_id):
|
||||
|
|
@ -247,7 +237,6 @@ def delete_feed(feed_id):
|
|||
conn.close()
|
||||
return redirect(url_for("feeds"))
|
||||
|
||||
|
||||
# Backup de feeds a CSV
|
||||
@app.route("/backup_feeds")
|
||||
def backup_feeds():
|
||||
|
|
@ -285,8 +274,7 @@ def backup_feeds():
|
|||
headers={"Content-Disposition": "attachment;filename=feeds_backup.csv"},
|
||||
)
|
||||
|
||||
|
||||
# Restaurar feeds desde CSV
|
||||
# Restaurar feeds desde CSV (robusto: bool/int/None/códigos)
|
||||
@app.route("/restore_feeds", methods=["GET", "POST"])
|
||||
def restore_feeds():
|
||||
msg = ""
|
||||
|
|
@ -301,8 +289,23 @@ def restore_feeds():
|
|||
conn = get_conn()
|
||||
cursor = conn.cursor()
|
||||
n_ok = 0
|
||||
for row in rows:
|
||||
msg_lines = []
|
||||
for i, row in enumerate(rows, 1):
|
||||
try:
|
||||
# -- robusto para activo (admite True/False/1/0/t/f/yes/no/vacío)
|
||||
activo_val = str(row.get("activo", "")).strip().lower()
|
||||
if activo_val in ["1", "true", "t", "yes"]:
|
||||
activo = True
|
||||
elif activo_val in ["0", "false", "f", "no"]:
|
||||
activo = False
|
||||
else:
|
||||
activo = True # valor por defecto
|
||||
|
||||
idioma = row.get("idioma", None)
|
||||
idioma = idioma.strip() if idioma else None
|
||||
if idioma == "":
|
||||
idioma = None
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO feeds (
|
||||
|
|
@ -320,35 +323,35 @@ def restore_feeds():
|
|||
fallos = EXCLUDED.fallos;
|
||||
""",
|
||||
{
|
||||
"id": row.get("id"),
|
||||
"id": int(row.get("id")),
|
||||
"nombre": row["nombre"],
|
||||
"descripcion": row.get("descripcion") or "",
|
||||
"url": row["url"],
|
||||
"categoria_id": row["categoria_id"],
|
||||
"pais_id": row["pais_id"],
|
||||
"idioma": row.get("idioma"),
|
||||
"activo": bool(int(row["activo"])),
|
||||
"categoria_id": int(row["categoria_id"]) if row["categoria_id"] else None,
|
||||
"pais_id": int(row["pais_id"]) if row["pais_id"] else None,
|
||||
"idioma": idioma,
|
||||
"activo": activo,
|
||||
"fallos": int(row.get("fallos", 0)),
|
||||
},
|
||||
)
|
||||
n_ok += 1
|
||||
except Exception as e:
|
||||
app.logger.error(f"Error insertando feed {row}: {e}")
|
||||
app.logger.error(f"Error insertando feed fila {i}: {e}")
|
||||
msg_lines.append(f"Error en fila {i}: {e}")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
msg = f"Feeds restaurados correctamente: {n_ok}"
|
||||
if msg_lines:
|
||||
msg += "<br>" + "<br>".join(msg_lines)
|
||||
return render_template("restore_feeds.html", msg=msg)
|
||||
|
||||
|
||||
@app.route("/noticias")
|
||||
def show_noticias():
|
||||
return home()
|
||||
|
||||
|
||||
# ================================
|
||||
# Lógica de procesado de feeds con control de fallos
|
||||
# ================================
|
||||
|
||||
def sumar_fallo_feed(cursor, feed_id):
|
||||
cursor.execute("UPDATE feeds SET fallos = fallos + 1 WHERE id = %s", (feed_id,))
|
||||
cursor.execute("SELECT fallos FROM feeds WHERE id = %s", (feed_id,))
|
||||
|
|
@ -357,11 +360,9 @@ def sumar_fallo_feed(cursor, feed_id):
|
|||
cursor.execute("UPDATE feeds SET activo = FALSE WHERE id = %s", (feed_id,))
|
||||
return fallos
|
||||
|
||||
|
||||
def resetear_fallos_feed(cursor, feed_id):
|
||||
cursor.execute("UPDATE feeds SET fallos = 0 WHERE id = %s", (feed_id,))
|
||||
|
||||
|
||||
def fetch_and_store():
|
||||
conn = None
|
||||
try:
|
||||
|
|
@ -459,7 +460,6 @@ def fetch_and_store():
|
|||
conn.close()
|
||||
app.logger.info(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Feeds procesados.")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Lanzador de la aplicación + scheduler
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue