TypeError ao enviar uma flag com conteúdo personalizado (flags require_message)

Descrição do Bug

Quando um usuário seleciona um tipo de sinalização que exige uma mensagem personalizada (por exemplo, notify_moderators, notify_user ou qualquer sinalização personalizada criada por um administrador com a opção “Exigir mensagem” ativada), preenche a mensagem e envia — o navegador lança um TypeError não capturado e a sinalização nunca é enviada.

Passos para Reproduzir

  1. Acesse qualquer postagem de tópico.
  2. Clique no botão de sinalização para abrir o modal de sinalização.
  3. Selecione um tipo de sinalização que exija uma mensagem (por exemplo, “Outra Coisa” / notify_moderators, ou qualquer sinalização personalizada criada em Admin → Sinalizações com “Exigir mensagem” ativada).
  4. Digite uma mensagem na área de texto (com comprimento suficiente para atender ao mínimo exigido).
  5. Clique no botão de envio.

Comportamento Esperado

A sinalização é enviada com sucesso.

Comportamento Real

O modal de sinalização fecha, mas a sinalização não é enviada. O console do navegador exibe:

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álise da Causa Raiz

A falha origina-se em Flag#create (flag.js:24):

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

O método postActionFor em PostFlag procura a sinalização selecionada pelo 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
  );
}

O PostSerializer do backend inclui uma entrada de sinalização em actions_summary apenas quando pelo menos um dos valores can_act, count ou acted é verdadeiro:

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

Para sinalizações com require_message: true (que são todas do tipo notify_type: true), o método post_can_act? define can_act: false quando already_did_flagging é verdadeiro — ou seja, o usuário já enviou anteriormente qualquer sinalização do tipo notificação naquele post. Nesse caso, a entrada está ausente em actions_summary, postActionFor retorna undefined e a falha ocorre.

Enquanto isso, Post#flagsAvailable (que controla o que o usuário pode selecionar na interface) usa o mapa actionByName construído no momento do carregamento da página, então a sinalização ainda pode aparecer como selecionável mesmo após actions_summary não mais contê-la.

Bug Secundário

Há também uma comparação incorreta em flag.gjs:

const NOTIFY_MODERATORS_KEY = "notify_moderators"; // string

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

f.id é um número, mas NOTIFY_MODERATORS_KEY é uma string, então === sempre retorna false e notifyModeratorsFlag é sempre undefined. Isso quebra a lógica do botão “Sinalizar para Revisão” em flagForReview().

Solução Sugerida

PostFlag#postActionFor deve usar o mapa actionByName (indexado por name_key) em vez de buscar em actions_summary pelo id, de forma consistente com como TopicFlag#postActionFor já funciona:

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

E notifyModeratorsFlag deve comparar por name_key em vez de id:

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

Versão do Discourse

2026.5.0-latest

Reprodutível em

  • Última versão da branch main
1 curtida