Error TypeError al enviar una bandera con contenido personalizado (banderas require_message)

Descripción del error

Cuando un usuario selecciona un tipo de reporte que requiere un mensaje personalizado (por ejemplo, notify_moderators, notify_user o cualquier reporte personalizado creado por un administrador con la opción “Requerir mensaje” activada), completa el mensaje y lo envía, el navegador lanza un TypeError no capturado y el reporte nunca se envía.

Pasos para reproducir

  1. Visita cualquier publicación de un tema.
  2. Haz clic en el botón de reporte para abrir el modal de reportes.
  3. Selecciona un tipo de reporte que requiera un mensaje (por ejemplo, “Otra cosa” / notify_moderators, o cualquier reporte personalizado creado en Administración → Reportes con la opción “Requerir mensaje” activada).
  4. Escribe un mensaje en el área de texto (lo suficientemente largo para superar la longitud mínima).
  5. Haz clic en el botón de enviar.

Comportamiento esperado

El reporte se envía correctamente.

Comportamiento real

El modal de reporte se cierra, pero el reporte no se envía. La consola del navegador muestra:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'act')
    at n.create (flag.js:24:8)
    at S.createFlag (flag.gjs:205:32)
    at S.takeAction (flag.gjs:196:12)
    at m.perform (reviewable-bundled-action.gjs:47:17)
    at ej._boundaryActionHandler (select-kit.js:685:34)
    ...

Análisis de la causa raíz

El fallo se origina en Flag#create (flag.js:24):

create(flagModal, opts) {
  const postAction = this.postActionFor(flagModal); // devuelve undefined
  // ...
  postAction.act(...) // ← TypeError: Cannot read properties of undefined
}

postActionFor en PostFlag busca el reporte seleccionado por su id numérico dentro de actions_summary:

// post-flag.js
postActionFor(flagModal) {
  return flagModal.args.model.flagModel.actions_summary.find(
    (item) => item.id === flagModal.selected.id
  );
}

El PostSerializer del backend solo incluye una entrada de reporte en actions_summary cuando al menos uno de can_act, count o acted es verdadero:

result << summary if summary[:can_act] || summary[:count] || summary[:acted]

Para los reportes con require_message: true (que son todos notify_type: true), post_can_act? establece can_act: false cuando already_did_flagging es verdadero; es decir, cuando el usuario ya ha enviado algún reporte de tipo notificación en esa publicación. En ese caso, la entrada está ausente en actions_summary, postActionFor devuelve undefined y se produce el fallo.

Mientras tanto, Post#flagsAvailable (que controla qué puede seleccionar el usuario en la interfaz) utiliza el mapa actionByName construido al cargar la página, por lo que el reporte puede seguir apareciendo como seleccionable incluso después de que actions_summary ya no lo contenga.

Error secundario

También hay una comparación incorrecta en flag.gjs:

const NOTIFY_MODERATORS_KEY = "notify_moderators"; // cadena

get notifyModeratorsFlag() {
  return this.flagsAvailable.find((f) => f.id === NOTIFY_MODERATORS_KEY);
  //                                      ^ número   ^ cadena — siempre falso
}

f.id es un número, pero NOTIFY_MODERATORS_KEY es una cadena, por lo que === siempre devuelve false y notifyModeratorsFlag siempre es undefined. Esto rompe la lógica del botón “Reportar para revisión” en flagForReview().

Solución sugerida

PostFlag#postActionFor debería utilizar el mapa actionByName (indexado por name_key) en lugar de buscar en actions_summary por id, de manera coherente con cómo ya funciona TopicFlag#postActionFor:

// post-flag.js
postActionFor(flagModal) {
  return flagModal.args.model.flagModel.actionByName[
    flagModal.selected.name_key
  ];
}

Y notifyModeratorsFlag debería comparar por name_key en lugar de por id:

get notifyModeratorsFlag() {
  return this.flagsAvailable.find((f) => f.name_key === NOTIFY_MODERATORS_KEY);
}

Versión de Discourse

2026.5.0-latest

Reproducible en

  • Última rama main
1 me gusta