b5d46fad5c
- añade django.middleware.csrf.CsrfViewMiddleware a MIDDLEWARE (estaba ausente:
el CSRF estaba desactivado en todo el sitio)
- head.html: $.ajaxSetup envía X-CSRFToken en todo POST AJAX de jQuery + expone
window.CSRF_TOKEN (fuerza la cookie csrftoken en cada página)
- store_novawow.html: el fetch() nativo ahora manda X-CSRFToken (era el único que
se rompía al activar el middleware)
- register.html: añade {% csrf_token %} al formulario
- retira @csrf_exempt de login/register/restore_character/restore_items
(solo los webhooks stripe/sumup siguen exentos)
- auditoría previa: el resto de POST (AJAX jQuery + forms nativos con token) ya cubierto
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
99 lines
4.3 KiB
Markdown
99 lines
4.3 KiB
Markdown
# Foro integrado (app `forum`)
|
||
|
||
Foro de comunidad reimplementado en Django dentro de NovaWoW, con el **diseño
|
||
del propio sitio** (usa los `partials` head/header/footer). Portado desde la app
|
||
Symfony *NovaWeb-main*, contra las **mismas tablas** en la base de datos
|
||
`acore_web`.
|
||
|
||
## Arquitectura
|
||
|
||
- **BD**: `acore_web` (5ª conexión Django, `DB_NAME_WEB`). Acceso por SQL directo
|
||
(`connections['acore_web']`), mismo estilo que el resto del proyecto.
|
||
- **Tablas**: `forum_categories`, `forums`, `forum_topics`, `forum_posts`,
|
||
`forum_reads`. (La tabla legacy `forum_forums` NO se usa.)
|
||
- **Identidad del autor**: la cuenta de juego en sesión de NovaWoW
|
||
(`session['account_id']` / `session['username']`). No usa las cookies del
|
||
proyecto original.
|
||
|
||
## Funcionalidad (completa)
|
||
|
||
- Portada con categorías y foros (contadores de temas/mensajes, último tema).
|
||
- Ver foro: lista de temas paginada.
|
||
- Ver tema: posts paginados, con panel de autor (rol, registro, nº de mensajes).
|
||
- 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) **paginado** en `/es/forum/search`.
|
||
- Contador de **visitas** por tema (columna opcional `forum_topics.views`).
|
||
- Perfil público básico (`/es/profile/<usuario>`).
|
||
- El autor se muestra con un **nombre legible** (parte local del email de la
|
||
cuenta) en vez de `<bnetId>#1`.
|
||
|
||
Rutas bajo `/es/forum...` (idénticas al original: `app_forum`, `forum_view`,
|
||
`forum_topic`, `forum_create_topic`, etc.).
|
||
|
||
## Modelo de permisos (simplificado)
|
||
|
||
En vez de la matriz `group_level`×`permission` del original (enrevesada y con
|
||
acciones que quedaban deshabilitadas por falta de filas), se usa un modelo claro
|
||
en `forum/permissions.py`:
|
||
|
||
- **Ver**: foros públicos (`visibility=1`, `deleted=0`) visibles para todos.
|
||
- **Publicar / responder / crear tema**: cualquier usuario con sesión iniciada y
|
||
cuenta de juego seleccionada.
|
||
- **Editar / borrar** un post: su autor, o un moderador.
|
||
- **Moderar**: cuentas con `gmlevel >= FORUM_MOD_GMLEVEL` (por defecto **2**),
|
||
leído de `acore_auth.account_access`.
|
||
|
||
## Seguridad
|
||
|
||
- El texto de los posts se **sanea con `nh3`** (allowlist de etiquetas) al
|
||
guardar — `forum/sanitize.py` — evitando el XSS que tenía el original (que
|
||
renderizaba HTML del editor sin filtrar). Se renderiza con `|safe` ya saneado.
|
||
- **Todas** las acciones que modifican datos (publicar, responder, editar, mover,
|
||
bloquear/desbloquear, fijar, borrar/restaurar temas y posts) van por **POST**, y
|
||
las vistas mutadoras llevan **`@csrf_protect`** (fuerza la validación CSRF por
|
||
vista aunque el middleware global no esté activo).
|
||
- El HTML de los posts también se **sanea al renderizar** con el filtro
|
||
`forum_safe` (defensa en profundidad frente a datos heredados sin sanear).
|
||
- Acceso a temas de foros ocultos/borrados bloqueado también por URL directa
|
||
(no solo en los listados).
|
||
|
||
> ✅ **CSRF global activado** (todo el portal): `novawow/settings.py` ya incluye
|
||
> `django.middleware.csrf.CsrfViewMiddleware`. Las peticiones AJAX (jQuery) envían
|
||
> la cabecera `X-CSRFToken` automáticamente (`$.ajaxSetup` en `partials/head.html`),
|
||
> los formularios nativos llevan `{% csrf_token %}`, y solo los webhooks externos
|
||
> (`stripe_webhook`, `sumup_webhook`) mantienen `@csrf_exempt`.
|
||
|
||
## Editor
|
||
|
||
Los mensajes se escriben con **CKEditor 5** (el mismo editor que usa el resto de
|
||
NovaWoW), vía `forum/forms.py` (`TopicForm`, `ReplyForm`, `EditPostForm`). El
|
||
HTML que produce el editor se **sanea con nh3** al guardar, así que el rich text
|
||
es seguro.
|
||
|
||
## Despliegue
|
||
|
||
1. Crear/usar la BD `acore_web` y aplicar el esquema:
|
||
```bash
|
||
mysql acore_web < sql/forum_schema.sql
|
||
```
|
||
(Si ya existe la BD del portal Symfony con esas tablas, apunta `DB_NAME_WEB`
|
||
a ella y omite este paso.)
|
||
- Opcional (contador de visitas): `mysql acore_web < sql/forum_views.sql`.
|
||
El foro detecta la columna automáticamente y funciona sin ella.
|
||
2. Configurar variables de entorno:
|
||
```
|
||
DB_NAME_WEB=acore_web
|
||
FORUM_MOD_GMLEVEL=2
|
||
FORUM_TOPICS_PER_PAGE=20
|
||
FORUM_POSTS_PER_PAGE=15
|
||
```
|
||
3. El enlace «FOROS» del menú COMUNIDAD ya apunta al foro interno (`/es/forum`).
|
||
|
||
## Notas / posibles mejoras
|
||
|
||
- Sistema de nicks propio del foro (ahora el nombre visible es la parte local del
|
||
email de la cuenta).
|
||
- Avatares de usuario y firmas.
|