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
- Accédez à n’importe quel sujet de discussion.
- Cliquez sur le bouton de signalement pour ouvrir la fenêtre modale.
- 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). - Saisissez un message dans la zone de texte (assez long pour respecter la longueur minimale).
- 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