Описание ошибки
Когда пользователь выбирает тип флага, требующий пользовательского сообщения (например, notify_moderators, notify_user или любой созданный администратором пользовательский флаг с включённой опцией «Требовать сообщение»), заполняет сообщение и отправляет форму — браузер выбрасывает необработанную ошибку TypeError, и флаг никогда не отправляется.
Шаги для воспроизведения
- Перейдите к любой теме в обсуждении.
- Нажмите кнопку «Пожаловаться», чтобы открыть модальное окно флага.
- Выберите тип флага, требующий сообщения (например, «Что-то ещё» /
notify_moderatorsили любой пользовательский флаг, созданный в разделе Администрирование → Флаги с включённой опцией «Требовать сообщение»). - Введите сообщение в текстовое поле (достаточно длинное, чтобы пройти проверку минимальной длины).
- Нажмите кнопку «Отправить».
Ожидаемое поведение
Флаг успешно отправляется.
Фактическое поведение
Модальное окно флага закрывается, но сам флаг не отправляется. В консоли браузера отображается:
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)
...
Анализ первопричины
Сбой происходит в методе Flag#create (flag.js:24):
create(flagModal, opts) {
const postAction = this.postActionFor(flagModal); // возвращает undefined
// ...
postAction.act(...) // ← TypeError: Cannot read properties of undefined
}
Метод postActionFor в PostFlag ищет выбранный флаг по числовому id внутри actions_summary:
// post-flag.js
postActionFor(flagModal) {
return flagModal.args.model.flagModel.actions_summary.find(
(item) => item.id === flagModal.selected.id
);
}
Бэкенд-сериализатор PostSerializer включает запись флага в actions_summary только если хотя бы одно из значений can_act, count или acted истинно:
result << summary if summary[:can_act] || summary[:count] || summary[:acted]
Для флагов с require_message: true (которые все имеют notify_type: true) метод post_can_act? устанавливает can_act: false, когда already_did_flagging истинно — то есть, если пользователь ранее отправлял любой флаг типа уведомлений на этот пост. В таком случае запись отсутствует в actions_summary, postActionFor возвращает undefined, и возникает сбой.
Тем временем Post#flagsAvailable (который определяет, какие флаги доступны для выбора в интерфейсе) использует карту actionByName, построенную при загрузке страницы, поэтому флаг может по-прежнему отображаться как доступный для выбора, даже если он больше не присутствует в actions_summary.
Вторичная ошибка
Также в flag.gjs есть ошибка в сравнении:
const NOTIFY_MODERATORS_KEY = "notify_moderators"; // строка
get notifyModeratorsFlag() {
return this.flagsAvailable.find((f) => f.id === NOTIFY_MODERATORS_KEY);
// ^ число ^ строка — всегда false
}
f.id — это число, а NOTIFY_MODERATORS_KEY — строка, поэтому === всегда возвращает false, и notifyModeratorsFlag всегда равен undefined. Это нарушает логику кнопки «Пожаловаться на рассмотрение» в методе flagForReview().
Предлагаемое исправление
Метод PostFlag#postActionFor должен использовать карту actionByName (индексируемую по name_key), а не искать в actions_summary по id, что соответствует тому, как уже работает TopicFlag#postActionFor:
// post-flag.js
postActionFor(flagModal) {
return flagModal.args.model.flagModel.actionByName[
flagModal.selected.name_key
];
}
А notifyModeratorsFlag должен сравнивать по name_key, а не по id:
get notifyModeratorsFlag() {
return this.flagsAvailable.find((f) => f.name_key === NOTIFY_MODERATORS_KEY);
}
Версия Discourse
2026.5.0-latest
Воспроизводится на
- Последняя ветка
main