Erreur TypeError lors de la soumission d'un drapeau avec du contenu personnalisé (drapeaux require_message)

Description du bogue

Lorsqu’un utilisateur sélectionne un type de signalement nécessitant un message personnalisé (par exemple notify_moderators, notify_user, ou tout signalement personnalisé créé par un administrateur avec l’option « Message requis » activée), remplit le message et soumet le formulaire, le navigateur lève une erreur TypeError non capturée et le signalement n’est jamais envoyé.

Étapes pour reproduire le problème

  1. Accédez à n’importe quel sujet de discussion.
  2. Cliquez sur le bouton de signalement pour ouvrir la fenêtre modale.
  3. Sélectionnez un type de signalement nécessitant un message (par exemple « Autre chose » / notify_moderators, ou tout signalement personnalisé créé dans Administration → Signalements avec l’option « Message requis » activée).
  4. Saisissez un message dans la zone de texte (assez long pour respecter la longueur minimale).
  5. Cliquez sur le bouton de soumission.

Comportement attendu

Le signalement est soumis avec succès.

Comportement réel

La fenêtre modale de signalement se ferme, mais le signalement n’est pas soumis. La console du navigateur affiche :

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)
    ...

Analyse de la cause racine

Le plantage provient de Flag#create (flag.js:24) :

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

La méthode postActionFor dans PostFlag recherche le signalement sélectionné par son id numérique dans actions_summary :

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

Le sérialiseur backend PostSerializer n’inclut une entrée de signalement dans actions_summary que si au moins l’un des champs can_act, count ou acted est vrai :

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

Pour les signalements avec require_message: true (qui sont tous de type notify_type: true), la méthode post_can_act? définit can_act: false lorsque already_did_flagging est vrai — c’est-à-dire lorsque l’utilisateur a déjà soumis un signalement de type notification sur ce message. Dans ce cas, l’entrée est absente de actions_summary, postActionFor retourne undefined, et le plantage se produit.

Pendant ce temps, Post#flagsAvailable (qui contrôle ce que l’utilisateur peut sélectionner dans l’interface) utilise la carte actionByName construite au chargement de la page, de sorte que le signalement peut toujours apparaître comme sélectionnable même si actions_summary ne le contient plus.

Bogue secondaire

Il existe également une comparaison incorrecte dans flag.gjs :

const NOTIFY_MODERATORS_KEY = "notify_moderators"; // chaîne de caractères

get notifyModeratorsFlag() {
  return this.flagsAvailable.find((f) => f.id === NOTIFY_MODERATORS_KEY);
  //                                      ^ nombre   ^ chaîne — toujours faux
}

f.id est un nombre, mais NOTIFY_MODERATORS_KEY est une chaîne, donc === retourne toujours false et notifyModeratorsFlag est toujours undefined. Cela rompt la logique du bouton « Signaler pour examen » dans flagForReview().

Solution proposée

PostFlag#postActionFor devrait utiliser la carte actionByName (indexée par name_key) au lieu de rechercher dans actions_summary par id, conformément au fonctionnement déjà en place dans TopicFlag#postActionFor :

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

Et notifyModeratorsFlag devrait comparer par name_key au lieu de id :

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

Version de Discourse

2026.5.0-latest

Reproductible sur

  • La dernière branche main
2 « J'aime »

Merci pour votre signalement, nous allons jeter un coup d’œil. N’hésitez pas à soumettre une PR si vous le souhaitez.

J’ai essayé de reproduire le problème localement, mais sans succès. Pouvez-vous le reproduire si vous activez le mode sans échec ?

1 « J'aime »

Je pense qu’un signalement du sujet une seule fois ne provoquera pas cela, car alors already_did_flagging devrait être false. Habituellement, il n’est pas possible de signaler à nouveau le même message. Mais après un signalement en tant que « autre chose », vous pouvez toujours signaler en tant que « illégal ». Le résultat dans ce cas est :

1 « J'aime »

Maintenant, j’ai réussi à reproduire le problème :

Bien que signaler deux fois le même message soit généralement impossible, il semble que ce soit différent dans les sujets imbriqués. Donc :

  1. Créez un sujet avec quelques réponses imbriquées
  2. Signalez la réponse comme « autre chose » et soumettez le signalement
  3. Cliquez à nouveau sur l’icône de signalement
    Résultat attendu : Seule l’option « C’est illégal » est disponible, comme pour les messages dans les sujets sans mode imbriqué.
    Résultat réel : Toutes les raisons de signalement sauf « autre chose » sont disponibles.
  4. Choisissez une autre raison, soumettez le signalement et vérifiez la console du navigateur
1 « J'aime »

Un peu en retard, mais j’y travaille maintenant.

Ce que je ne vois pas, c’est « C’est illégal », même pour le mode non imbriqué. J’ai mis à jour le mode imbriqué pour qu’il corresponde au comportement des sujets non imbriqués, mais les deux finissent par ressembler à ceci lorsque vous tentez de signaler à nouveau :

1 « J'aime »

J’ai simplement suivi les étapes ci-dessus sur un sujet sans réponses imbriquées.

Comme vous pouvez le voir ci-dessous, le message a déjà été signalé pour modération par l’utilisateur, et cliquer à nouveau sur la fenêtre de signalement donne :


En regardant les paramètres de mon site, allow_all_users_to_flag_illegal_content semble être ce qui permet aux utilisateurs de continuer à signaler comme « illégal » après avoir choisi une autre option.

1 « J'aime »

Ah, ça a réglé le problème, merci ! La correction devrait être disponible assez rapidement.

1 « J'aime »

La correction du bug principal est désormais dans latest et devrait résoudre le problème. C’est-à-dire qu’elle devrait être identique aux réponses aux sujets non imbriqués.


J’ai décidé de séparer celui-ci car il ne s’agit pas du même comportement, et je le corrigerai également bientôt.

1 « J'aime »

La suite a également été fusionnée. La comparaison erronée nous jouait en fait un tour — si la comparaison avait été corrigée correctement, elle aurait permis aux administrateurs/modérateurs de soumettre des signalements sans raison. Nous souhaitons qu’une raison soit obligatoire pour soumettre des signalements, j’ai donc supprimé le code au lieu de le corriger afin d’éviter toute confusion future.