Ошибка 'FAILED' при попытке снять значок 'Bug Reporter'

Эта ошибка существует уже давно. Я исследовал её в прошлом году, и вот шаги для её воспроизведения:

  1. Как администратор, установите max favorite badges (максимальное количество избранных значков) в значение 2 и создайте хотя бы один значок, который можно получить несколько раз.
  2. Как обычный пользователь, добавьте два значка в избранное, один из которых — значок, который можно получить несколько раз (назовём его Значок A).
  3. Как администратор, выдайте пользователю Значок A повторно.
  4. Как обычный пользователь, обновите страницу и попробуйте убрать звезду с Значка A. Вы столкнётесь с ошибкой.

Причина ошибки заключается в том, что каждый раз при выдаче значка, который можно получить несколько раз, в базе данных создаётся новая запись user_badge. Однако, если пользователь уже добавил этот значок в избранное, а затем получил его снова, новая запись user_badge автоматически не помечается как is_favorite. Когда пользователь пытается убрать звезду с Значка A, фронтенд по умолчанию отправляет ID самой свежей записи user_badge. Поскольку эта запись не помечена как is_favorite, бэкенд предполагает, что пользователь пытается добавить новый значок в избранное (вместо того чтобы убрать его из избранного), что превышает лимит max favorite badges, и возникает ошибка.

Соответствующий код находится по адресу:

Одно из возможных решений — изменить строку 131 следующим образом:

if UserBadge.where(badge: user_badge.badge, user: user_badge.user).pluck(:is_favorite).any? &&

Однако это не устраняет полностью несоответствие записей в базе данных.

Как временное решение, обычный пользователь может убрать все значки из избранного, выполнив следующий JavaScript-код в консоли:

const user_name = require("discourse/models/user").default.current().username;
const badges = await require("discourse/models/user-badge").default.findByUsername(user_name);
const favorites = new Map();
badges.filter((b)=>b.is_favorite).forEach((b)=>favorites.set(b.badge_id,b));
favorites.forEach((b)=>b.favorite());
9 лайков