From fd49d6cd96b465372baf0a382e5cda3f7c84d23d Mon Sep 17 00:00:00 2001 From: adevopg Date: Sun, 12 Jul 2026 17:18:34 +0000 Subject: [PATCH] Foro: buscador de temas y nombre de autor legible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - forum_search: busca temas por título y contenido (foros visibles) - db.get_display_name: nombre visible del autor = parte local del email de la cuenta (en vez de #1), usado en el panel de posts y la lista de temas - buscador en la portada del foro + plantilla search.html - docs/FORO.md actualizado Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/FORO.md | 9 ++++-- forum/db.py | 47 ++++++++++++++++++++++++++++- forum/templates/forum/forum.html | 2 +- forum/templates/forum/index.html | 5 ++++ forum/templates/forum/search.html | 49 +++++++++++++++++++++++++++++++ forum/templates/forum/topic.html | 2 +- forum/urls.py | 1 + forum/views.py | 15 ++++++++++ 8 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 forum/templates/forum/search.html diff --git a/docs/FORO.md b/docs/FORO.md index cce3480..071592b 100644 --- a/docs/FORO.md +++ b/docs/FORO.md @@ -23,7 +23,10 @@ Symfony *NovaWeb-main*, contra las **mismas tablas** en la base de datos - Crear tema, responder, editar y borrar el post propio. - Moderación: fijar/desfijar, bloquear/desbloquear, mover, borrar/restaurar temas y posts. +- Buscador de temas (por título y contenido) en `/es/forum/search`. - Perfil público básico (`/es/profile/`). +- El autor se muestra con un **nombre legible** (parte local del email de la + cuenta) en vez de `#1`. Rutas bajo `/es/forum...` (idénticas al original: `app_forum`, `forum_view`, `forum_topic`, `forum_create_topic`, etc.). @@ -76,5 +79,7 @@ es seguro. ## Notas / posibles mejoras -- El autor se muestra como el nombre de cuenta de juego (`#1`); se podría - mapear a un nick o al email como en «Mi cuenta». +- Sistema de nicks propio del foro (ahora el nombre visible es la parte local del + email de la cuenta). +- Paginación/relevancia en los resultados de búsqueda (ahora lista los 50 temas + más recientes que coinciden). diff --git a/forum/db.py b/forum/db.py index 524bcde..fdad3bb 100644 --- a/forum/db.py +++ b/forum/db.py @@ -231,9 +231,11 @@ def get_author_info(poster_id): Datos del autor para mostrar en los posts: nivel GM, fecha de registro y nº de mensajes. Cruza acore_auth (account/account_access) y acore_web. """ - info = {'gmlevel': 0, 'joindate': None, 'post_count': 0, 'status': 'Miembro'} + info = {'gmlevel': 0, 'joindate': None, 'post_count': 0, 'status': 'Miembro', + 'display_name': None} if not poster_id: return info + info['display_name'] = get_display_name(poster_id) try: with connections['acore_auth'].cursor() as cursor: cursor.execute("SELECT MAX(gmlevel) FROM account_access WHERE id = %s", [poster_id]) @@ -308,6 +310,49 @@ def mark_read(user_id, topic_id): ) +def get_display_name(poster_id): + """ + Nombre legible del autor a partir de su cuenta: parte local del email + (antes de la @). Si no hay email, devuelve None (la plantilla usa el poster). + """ + if not poster_id: + return None + try: + with connections['acore_auth'].cursor() as cursor: + cursor.execute( + "SELECT email, reg_mail FROM account WHERE id = %s", [poster_id] + ) + row = cursor.fetchone() + except Exception: + return None + if not row: + return None + email = (row[0] or row[1] or '').strip() + if '@' in email: + return email.split('@', 1)[0] + return None + + +def search_topics(query, limit=50): + """Busca temas por título o por contenido de sus posts (foros visibles).""" + like = f"%{query}%" + with _conn().cursor() as cursor: + cursor.execute( + """ + SELECT DISTINCT t.id, t.name, t.poster, t.poster_id, t.forum_id, + t.created, f.name AS forum_name + FROM forum_topics t + JOIN forums f ON f.id = t.forum_id AND f.visibility = 1 AND f.deleted = 0 + LEFT JOIN forum_posts p ON p.topic_id = t.id AND p.deleted = 0 + WHERE t.deleted = 0 AND (t.name LIKE %s OR p.text LIKE %s) + ORDER BY t.updated_at DESC + LIMIT %s + """, + [like, like, limit], + ) + return _dictfetchall(cursor) + + def list_forums_for_move(exclude_forum_id=None): """Lista de foros visibles para el desplegable de 'mover tema'.""" with _conn().cursor() as cursor: diff --git a/forum/templates/forum/forum.html b/forum/templates/forum/forum.html index c100242..721e704 100644 --- a/forum/templates/forum/forum.html +++ b/forum/templates/forum/forum.html @@ -29,7 +29,7 @@ {% if topic.moved %}Movido{% endif %} {{ topic.name }} -
por {{ topic.poster }} · {{ topic.created }}
+
por {{ topic.display_poster }} · {{ topic.created }}
{{ topic.post_count }} respuestas
diff --git a/forum/templates/forum/index.html b/forum/templates/forum/index.html index ee4e70e..e11cc75 100644 --- a/forum/templates/forum/index.html +++ b/forum/templates/forum/index.html @@ -12,6 +12,11 @@
{% include 'forum/_style.html' %}
+ {% for category in categories %}
{{ category.name }}
diff --git a/forum/templates/forum/search.html b/forum/templates/forum/search.html new file mode 100644 index 0000000..3d7681f --- /dev/null +++ b/forum/templates/forum/search.html @@ -0,0 +1,49 @@ + + + {% include 'partials/head.html' %} + {% include 'partials/header.html' %} + {% include 'partials/video.html' %} + +
+
+
+

Buscar en el foro

+
+
+ {% include 'forum/_style.html' %} +
+ + + {% if query %} +

Resultados para «{{ query }}»: {{ results|length }}

+ {% for topic in results %} +
+
+ {{ topic.name }} +
en {{ topic.forum_name }} · por {{ topic.display_poster }} · {{ topic.created }}
+
+
+ {% empty %} +

No se encontraron temas.

+ {% endfor %} + {% else %} +

Escribe al menos 2 caracteres para buscar.

+ {% endif %} + + +
+
+
+
+
+
+ + {% include 'partials/social.html' %} + {% include 'partials/footer.html' %} + {% include 'partials/final.html' %} diff --git a/forum/templates/forum/topic.html b/forum/templates/forum/topic.html index 7e25682..f74f4fc 100644 --- a/forum/templates/forum/topic.html +++ b/forum/templates/forum/topic.html @@ -21,7 +21,7 @@
{{ post.author.status }}
diff --git a/forum/urls.py b/forum/urls.py index 06e9997..8db266a 100644 --- a/forum/urls.py +++ b/forum/urls.py @@ -6,6 +6,7 @@ from . import views # que la genérica forum//... urlpatterns = [ path('forum', views.index, name='app_forum'), + path('forum/search', views.search, name='forum_search'), # Temas path('forum/topic//reply', views.reply_to_topic, name='forum_post_reply'), diff --git a/forum/views.py b/forum/views.py index 21f6c45..d080f15 100644 --- a/forum/views.py +++ b/forum/views.py @@ -75,6 +75,8 @@ def view_forum(request, forum_id, page=1): total = db.count_topics(forum_id) pag, offset = _paginate(total, page, settings.FORUM_TOPICS_PER_PAGE) topics = db.get_topics(forum_id, offset, settings.FORUM_TOPICS_PER_PAGE) + for t in topics: + t['display_poster'] = db.get_display_name(t['poster_id']) or t['poster'] return render(request, 'forum/forum.html', _base_context(request, { 'forum': forum, @@ -83,6 +85,19 @@ def view_forum(request, forum_id, page=1): })) +def search(request): + query = (request.GET.get('q') or '').strip() + results = [] + if len(query) >= 2: + results = db.search_topics(query) + for r in results: + r['display_poster'] = db.get_display_name(r['poster_id']) or r['poster'] + return render(request, 'forum/search.html', _base_context(request, { + 'query': query, + 'results': results, + })) + + def view_topic(request, topic_id, page=1): topic = db.get_topic(topic_id, include_hidden=perm.is_moderator(request)) if not topic: