From 4ca48836c9fc02c32d329367004cf42b830d6c97 Mon Sep 17 00:00:00 2001 From: jlimolina Date: Tue, 27 May 2025 12:36:35 +0200 Subject: [PATCH] =?UTF-8?q?A=C3=B1adida=20restauraci=C3=B3n=20de=20feeds?= =?UTF-8?q?=20desde=20CSV,=20mejoras=20en=20UI,=20y=20campo=20descripci?= =?UTF-8?q?=C3=B3n=20en=20feeds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 68 +++++++++++---- templates/base.html | 17 ++++ templates/edit_feed.html | 68 +++++++-------- templates/index.html | 157 ++++++++++++++++++++--------------- templates/noticias.html | 146 +++++++++++++++++--------------- templates/restore_feeds.html | 24 ++++++ 6 files changed, 298 insertions(+), 182 deletions(-) create mode 100644 templates/base.html create mode 100644 templates/restore_feeds.html diff --git a/app.py b/app.py index f62bd61..9d15d20 100644 --- a/app.py +++ b/app.py @@ -27,7 +27,6 @@ def home(): categorias = [] continentes = [] paises = [] - # Lee los filtros enviados por GET cat_id = request.args.get('categoria_id') cont_id = request.args.get('continente_id') pais_id = request.args.get('pais_id') @@ -38,7 +37,6 @@ def home(): categorias = cursor.fetchall() cursor.execute("SELECT id, nombre FROM continentes ORDER BY nombre") continentes = cursor.fetchall() - # Filtra países si hay continente seleccionado, si no trae todos if cont_id: cursor.execute("SELECT id, nombre, continente_id FROM paises WHERE continente_id = %s ORDER BY nombre", (cont_id,)) else: @@ -92,15 +90,14 @@ def feeds(): try: conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() - # Feeds con país/categoría (incluye nombres) + # Feeds con descripción cursor.execute(""" - SELECT f.id, f.nombre, f.url, f.categoria_id, f.pais_id, f.activo, c.nombre, p.nombre + SELECT f.id, f.nombre, f.descripcion, f.url, f.categoria_id, f.pais_id, f.activo, c.nombre, p.nombre FROM feeds f LEFT JOIN categorias_estandar c ON f.categoria_id = c.id LEFT JOIN paises p ON f.pais_id = p.id """) feeds = cursor.fetchall() - # Categorías, continentes y países para los selects cursor.execute("SELECT id, nombre FROM categorias_estandar ORDER BY nombre") categorias = cursor.fetchall() cursor.execute("SELECT id, nombre FROM continentes ORDER BY nombre") @@ -119,6 +116,7 @@ def feeds(): @app.route('/add', methods=['POST']) def add_feed(): nombre = request.form.get('nombre') + descripcion = request.form.get('descripcion') url = request.form.get('url') categoria_id = request.form.get('categoria_id') pais_id = request.form.get('pais_id') @@ -126,8 +124,8 @@ def add_feed(): conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() cursor.execute( - "INSERT INTO feeds (nombre, url, categoria_id, pais_id) VALUES (%s, %s, %s, %s)", - (nombre, url, categoria_id, pais_id) + "INSERT INTO feeds (nombre, descripcion, url, categoria_id, pais_id) VALUES (%s, %s, %s, %s, %s)", + (nombre, descripcion, url, categoria_id, pais_id) ) conn.commit() except mysql.connector.Error as db_err: @@ -146,17 +144,17 @@ def edit_feed(feed_id): cursor = conn.cursor(dictionary=True) if request.method == 'POST': nombre = request.form.get('nombre') + descripcion = request.form.get('descripcion') url_feed = request.form.get('url') categoria_id = request.form.get('categoria_id') pais_id = request.form.get('pais_id') activo = 1 if request.form.get('activo') == 'on' else 0 cursor.execute( - "UPDATE feeds SET nombre=%s, url=%s, categoria_id=%s, pais_id=%s, activo=%s WHERE id=%s", - (nombre, url_feed, categoria_id, pais_id, activo, feed_id) + "UPDATE feeds SET nombre=%s, descripcion=%s, url=%s, categoria_id=%s, pais_id=%s, activo=%s WHERE id=%s", + (nombre, descripcion, url_feed, categoria_id, pais_id, activo, feed_id) ) conn.commit() return redirect(url_for('feeds')) - # GET: Obtener datos actuales del feed cursor.execute("SELECT * FROM feeds WHERE id = %s", (feed_id,)) feed = cursor.fetchone() cursor.execute("SELECT id, nombre FROM categorias_estandar ORDER BY nombre") @@ -195,7 +193,7 @@ def backup_feeds(): conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() cursor.execute(""" - SELECT f.id, f.nombre, f.url, f.categoria_id, c.nombre AS categoria, f.pais_id, p.nombre AS pais, f.activo + SELECT f.id, f.nombre, f.descripcion, f.url, f.categoria_id, c.nombre AS categoria, f.pais_id, p.nombre AS pais, f.activo FROM feeds f LEFT JOIN categorias_estandar c ON f.categoria_id = c.id LEFT JOIN paises p ON f.pais_id = p.id @@ -209,7 +207,6 @@ def backup_feeds(): if conn: conn.close() - # CSV en memoria si = StringIO() cw = csv.writer(si) cw.writerow(header) @@ -222,7 +219,51 @@ def backup_feeds(): headers={"Content-Disposition": "attachment;filename=feeds_backup.csv"} ) -# (Antiguo /noticias, por compatibilidad) +# Restaurar feeds desde CSV +@app.route('/restore_feeds', methods=['GET', 'POST']) +def restore_feeds(): + msg = "" + if request.method == 'POST': + file = request.files.get('file') + if not file or not file.filename.endswith('.csv'): + msg = "Archivo no válido." + else: + file_stream = StringIO(file.read().decode('utf-8')) + reader = csv.DictReader(file_stream) + rows = list(reader) + conn = mysql.connector.connect(**DB_CONFIG) + cursor = conn.cursor() + n_ok = 0 + for row in rows: + try: + # Soporta CSV con o sin columna 'descripcion' + descripcion = row.get('descripcion') or "" + cursor.execute(""" + INSERT INTO feeds (nombre, descripcion, url, categoria_id, pais_id, activo) + VALUES (%s, %s, %s, %s, %s, %s) + ON DUPLICATE KEY UPDATE + nombre=VALUES(nombre), + descripcion=VALUES(descripcion), + url=VALUES(url), + categoria_id=VALUES(categoria_id), + pais_id=VALUES(pais_id), + activo=VALUES(activo) + """, ( + row['nombre'], + descripcion, + row['url'], + row['categoria_id'], + row['pais_id'], + int(row['activo']) + )) + n_ok += 1 + except Exception as e: + app.logger.error(f"Error insertando feed {row}: {e}") + conn.commit() + conn.close() + msg = f"Feeds restaurados correctamente: {n_ok}" + return render_template("restore_feeds.html", msg=msg) + @app.route('/noticias') def show_noticias(): return home() @@ -232,7 +273,6 @@ def fetch_and_store(): try: conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() - # Leer feeds activos con país/categoría cursor.execute("SELECT url, categoria_id, pais_id FROM feeds WHERE activo = TRUE") feeds = cursor.fetchall() except mysql.connector.Error as db_err: diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..fd16237 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,17 @@ + + + + + {% block title %}Noticias RSS{% endblock %} + + + + +
+ {% block content %}{% endblock %} +
+ + + diff --git a/templates/edit_feed.html b/templates/edit_feed.html index 7646c4d..beeea94 100644 --- a/templates/edit_feed.html +++ b/templates/edit_feed.html @@ -1,50 +1,42 @@ - - - - - Editar Feed RSS - - +{% extends "base.html" %} +{% block title %}Editar Feed RSS{% endblock %} +{% block content %}

Editar Feed

-
- -

- -

- -

- -

- -

- - Cancelar -
- - + +
+ + +
+ + + Cancelar + + +{% endblock %} diff --git a/templates/index.html b/templates/index.html index 065df9b..be77e4b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,10 +1,95 @@ - - - - - Gestión de Feeds RSS +{% extends "base.html" %} +{% block title %}Gestión de Feeds RSS{% endblock %} +{% block content %} +

Gestión de Feeds RSS

+ ← Volver a últimas noticias + +
+

Añadir un nuevo feed

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+

Lista de Feeds

+ ⬇️ Descargar backup de feeds (CSV) + 🔄 Restaurar feeds desde backup + + + + + + + + + + + + + {% for id, nombre, descripcion, url, categoria_id, pais_id, activo, cat_nom, pais_nom in feeds %} + + + + + + + + + {% else %} + + + + {% endfor %} + +
Nombre y descripciónURLCategoríaPaísActivoAcciones
+ {{ nombre }} + {% if descripcion %} +
{{ descripcion }}
+ {% endif %} +
{{ url }}{{ cat_nom or 'N/A' }}{{ pais_nom or 'N/A' }}{{ 'Sí' if activo else 'No' }} + Editar | + Eliminar +
No hay feeds aún.
+
+ + ← Volver a últimas noticias + - - -

Gestión de Feeds RSS

-

← Volver a últimas noticias

- - -

- ⬇️ Descargar backup de feeds (CSV) -

- -

Añadir un nuevo feed

-
- - - - - - - - -
- -

Lista de Feeds

- - -

← Volver a últimas noticias

- - +{% endblock %} diff --git a/templates/noticias.html b/templates/noticias.html index be0ab82..11dd72e 100644 --- a/templates/noticias.html +++ b/templates/noticias.html @@ -1,8 +1,82 @@ - - - - - Últimas Noticias RSS +{% extends "base.html" %} +{% block title %}Últimas Noticias RSS{% endblock %} +{% block content %} +

Últimas Noticias Recopiladas

+ ⚙️ Gestionar feeds RSS + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+

Noticias recientes

+ +
+ + ← Volver a gestión de feeds + - - -

Últimas Noticias Recopiladas

- - -

⚙️ Gestionar feeds RSS

- -
- - - - - -
- -
- - - -

← Volver a gestión de feeds

- - +{% endblock %} diff --git a/templates/restore_feeds.html b/templates/restore_feeds.html new file mode 100644 index 0000000..527f73d --- /dev/null +++ b/templates/restore_feeds.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% block title %}Restaurar Feeds RSS{% endblock %} +{% block content %} +

Restaurar feeds desde backup CSV

+
+
+ + + +
+ {% if msg %} +
+ {{ msg }} +
+ {% endif %} +

+ El archivo debe contener las columnas:
+ id, nombre, [descripcion,] url, categoria_id, categoria, pais_id, pais, activo
+ La columna descripcion es opcional. +

+
+ ← Volver a feeds +{% endblock %} +