Я создал новый запрос Support multiple-reactions per post (Retort style) о поддержке нескольких реакций на пост в стиле «возражение», поскольку другая ссылка предназначена только для предложения большего выбора реакций к единственной реакции, которую позволяет Discourse Reactions.
Плагин Retort не является #официальным, поэтому мы не можем влиять на то, когда сообщество прекратит его активную разработку и поддержку.
Всё, что мы можем сделать, — это по возможности информировать людей, чтобы у них было время найти альтернативу (или хотя бы предупредить участников, чтобы смягчить разочарование).
Надеюсь, что эти два #запроса на новые функции когда-нибудь будут реализованы в плагине reactions, но пока они находятся на стадии «хорошие идеи». Но я держу за них кулачки. ![]()
Я понимаю вашу позицию. Реальность такова, что ни я, ни Джеймс уже какое-то время не можем уделять достаточно времени полноценной поддержке Retort. Вы заметите, что последний коммит в репозитории был сделан более года назад (мной 21 июля 2021 года). Отлично, что плагин продолжал работать так долго — это свидетельство качества работы, вложенной Джеймсом при его создании.
Когда я говорю, что у меня нет времени, поверьте, я бы очень хотел его иметь! Мне каждый раз грустно, когда приходится принимать такие решения (как, например, с плагином Landing Pages). Я не создавал Retort, но потратил на него немало времени. Когда вы решаете отказаться от чего-то, это похоже на признание того, что то, что вы создали или любили, с чем проводили много часов, дней и недель своей жизни, должно умереть. Я знаю, что для Джеймса это было трудное решение, когда он понял, что должен двигаться дальше.
В отличие от этого, плагин Reactions поддерживается организацией Discourse.org, состоящей из более чем 60 человек, на постоянной основе. Он используется на ряде серверов клиентов Discourse.org. Да, у него пока нет тех же функций, что и у Retort, но я настоятельно рекомендую вам pursue разработку этой функции как направление для развития. Возможно, вы сможете убедить кого-то вроде меня или другого участника Pavilion внести недостающую функцию в плагин через PR. Это был бы разумный путь к достижению ваших долгосрочных целей.
Всегда есть Marketplace, если вы хотите заплатить разработчику, чтобы он возродил проект в это время. Но вам, возможно, придется делать это несколько раз или согласиться на договор о техническом обслуживании.
Полагаю, ответ — нет? Мне бы хотелось перейти на реакции и попытаться найти популярные из них…
Предполагаю, что это возможно, так как они где-то хранятся в базе данных. К сожалению, у меня нет этого плагина, установленного на тестовом сайте, чтобы проверить детали. Существует ли таблица discourse-retort-retorts или аналогичная?
Вот как получить строку, разделенную символом |, для используемых вами ретортов:
# ./launcher enter app
# rails c
retorts = {}
PostDetail.where(extra: 'retort').each do |p|
retort = p.key.split('|').first
(retorts[retort] ||= []) << p
end
retorts.length
retorts.keys.join('|')
Это даст вам:
- Сначала количество уникальных эмодзи ретортов, которые используются
- Затем сами реторты в формате, который можно вставить в конфигурацию реакций, возможно, после обрезки, если строка слишком длинная для интерфейса реакций.
Для меня получается такая строка:
tada|rage|money_with_wings|face_vomiting|crossed_fingers|grin|vulcan_salute|worried|slightly_smiling_face|dart|+1|relaxed|star_struck|upside_down_face|sweat_drops|astonished|frowning_face|champagne|heavy_plus_sign|bulb|joy|fireworks|zap|smile|fast_forward|grinning|clap|sandwich|heart_eyes|rofl|smiley|wave|ice_cream|sob|mortar_board|open_mouth|pray|grimacing|roll_eyes|arrow_right_hook|brain|wink|cry|nerd_face|slight_smile|confused|ok|thinking|it|heart|smirk|sleepy|eyes|disappointed|question|laughing|man_shrugging|drum|shushing_face|herb|man_facepalming|ear|scream|ok_hand|mantelpiece_clock|smiling_face_with_three_hearts|confetti_ball|sunglasses|nose|pirate_flag|neutral_face|sweat_smile|gift|pensive|dark_sunglasses|exclamation|call_me_hand|green_heart|face_with_monocle|blush|boom|hugs|stuck_out_tongue|zipper_mouth_face|slightly_frowning_face|face_with_raised_eyebrow|exploding_head|information_source|sailboat|fire|gun|carousel_horse|sparkles|hearts|pizza|frowning|drooling_face|-1|100|metal|partying_face|four_leaf_clover|grinning_face_with_smiling_eyes|scream_cat|person_shrugging|deciduous_tree|sunflower|see_no_evil|hear_no_evil|speak_no_evil|微笑|top|face_with_peeking_eye|face_with_hand_over_mouth|stethoscope|money_mouth_face"
Если вы хотите скопировать список существующих ретортов в пост в Discourse, чтобы обсудить, что оставить при миграции на реакции, вы можете вместо этого использовать следующее:
":" + retorts.keys.join(': :') + ':'
Для меня сейчас это такой набор:
“
:微笑:
”
Чтобы получить маркированный список эмодзи с количеством вхождений каждого:
retorts.keys.sort.each do |k|
puts "* :#{k}: #{retorts[k].length}"
end
Я не буду вставлять весь маркированный список эмодзи, но он начинается так:
161
1
1
1
9
2
2
23
3
Если вы хотите увидеть каждый пост, существующий для каждого эмодзи:
retorts.keys.sort.each do |k|
puts "* :#{k}: #{retorts[k].length}"
retorts[k].each do |r|
p = Post.find_by(id: r.post_id)
next if p.nil?
puts " * #{p.full_url}"
end
end
Это слишком длинно, чтобы вставить здесь!
Я не знаю, как мигрировать все — или часть — этих ретортов в реакции. В плагине реакций нет упоминания о ретортах, поэтому автоматической миграции не происходит. У меня 927 реакций с 116 уникальными эмодзи, которые я хочу перенести в реакции.
Я ожидаю, что в какой-то момент мне придётся решить эту проблему, желательно до того, как Retort просто перестанет работать; если я реализую миграцию, я планирую задокументировать это здесь. Но хотя бы знание того, что у вас есть, может вам помочь.
При написании экспериментального кода для миграции Retort на Reactions я обнаружил, что записи Retort не обновляются при изменении имён пользователей.
Я полагаю, что с Reactions это не так, поскольку PostActions ссылается на реальные записи пользователей, а не хранит имена пользователей в JSON-объекте внутри PostDetail.
В общем случае, если кто-то решит взять на себя разработку и поддержку Retort, ему следует рассмотреть возможность миграции с PostDetail на PostActions, следуя подходу, использованному в Reactions.
Аналогично, система не распознаёт удаление постов.
Мой Script framework to rearrange topics and categories получил новую функцию, которая выходит за рамки простого перемещения тем и категорий!
Я обычно не забываю предупреждать, что не знаю Ruby или Ruby on Rails, поэтому мой код скорее идиосинкразичен, чем идиоматичен. Но, судя по тестированию, он работает!
def migrateRetortToReactions(allowed:, likes: nil, emojimap: nil)
# мигрируем, где это возможно, не переопределяя существующие лайки
# это неизбежно упрощённое преобразование, согласованное только благодаря порядку PostDetail
# попытка предпочесть одну запись PostDetail другой не предпринимается
emojimap = {} if emojimap.nil?
allowed.each do |a|
emojimap[a] = a
end
retort = "retort".freeze
emojiType = "emoji".freeze
usermap = Hash.new { |hash, username| hash[username] = User.find_by_username(username) }
postmap = Hash.new { |hash, post_id| hash[post_id] = Post.find(post_id) }
likeType = PostActionType.where(name_key: "like").pluck(:id).first
PostDetail.where(extra: retort).each do |pd|
begin
p = postmap[pd.post_id]
rescue
# PostDetail не согласован относительно удаления
$stderr.puts sprintf("Не удалось найти пост для %d: %s / %s", pd.post_id, pd.key, pd.value)
next
end
emoji = pd.key.split('|').first
users = JSON.parse(pd.value)
users.each do |user|
u = usermap[user]
next if u.nil? # изменённое имя пользователя или удалённый пользователь оставляют «сиротские» Retorts
if likes.include?(emoji)
pa = PostAction.where(post_id: p.id, user_id: u.id, post_action_type_id: likeType).first
next unless pa.nil?
$stderr.puts sprintf("Добавляем лайк для Retort %s пользователя %s в %s", emoji, user, p.url)
PostActionCreator.create(u, p, :like, created_at: pd.created_at, silent: true)
elsif emojimap.has_key?(emoji)
e = emojimap[emoji]
r = DiscourseReactions::Reaction.where(post_id: p.id, reaction_type: emojiType, reaction_value: e).first_or_create
ru = DiscourseReactions::ReactionUser.where(user_id: u.id, post_id: p.id).first
next unless ru.nil?
$stderr.puts sprintf("Конвертируем Retort %s в Reaction %s для пользователя %s в %s", emoji, e, user, p.url)
DiscourseReactions::ReactionUser.create(reaction_id: r.id, user_id: u.id, post_id: p.id, created_at: pd.created_at)
else
$stderr.puts sprintf("Игнорируем несоответствующий Retort %s для пользователя %s в %s", emoji, user, p.url)
end
end
end
end
Я использую созданный мной фреймворк для предоставления YAML-конфигурации, которая выглядит так:
- migrateRetortToReactions:
allowed:
- rofl
- astonished
- crossed_fingers
- sob
- thinking
- grimacing
- frowning_face
- drum
likes:
- dart
- +1
- joy
- "100"
- brain
- heart
- heart_eyes
- hearts
emojimap:
rage: sob
four_leaf_clover: crossed_fingers
cry: sob
open_mouth: astonished
scream: frowning_face
Однако вы можете просто обернуть это в Ruby-скрипт, сделав эти аргументы буквальным Ruby-кодом, поместить его в директорию script/ и запустить.
Всем привет, как мы обсуждали в теме выше, я уже написал функцию миграции с Retort на Reactions, включая административный интерфейс.
Чтобы это решение было готово к использованию в production, разработчикам плагина Reactions потребуется внести небольшое изменение для улучшения абстракции кода в плагине Reactions.
Поддержка миграции на уровне production между двумя плагинами требует значительного обеспечения качества, иначе могут легко возникнуть проблемы, подобные этой.
Извините! Я пропустил эти посты и просто посмотрел в основной ветке. Это длинная тема…
Я согласен. Я полностью обошел этот вопрос. Дело не только в ReactionManager.toggle! — ведь действительно нужно передавать created_at, верно?
Переход на Reactions действительно меняет семантику функции «лайк», потому что нельзя отменить действие, если кто-то отредактирует свой пост. Я бы не сделал такой же выбор в реализации. ![]()
В любом случае, то, что я хочу сделать, — это управлять этим через скрипт, и у меня нет никакого интереса управлять этим через интерфейс. Я не целевая аудитория для UI, так что, возможно, наличие моего хака не повредит.
Разумеется, я не хотел отговаривать вас от написания этого для собственных нужд, но я бы не рекомендовал другим сайтам использовать это, если они не знакомы с кодом и структурой данных.
Суть в том, что плагин Reactions в настоящее время написан не так, чтобы обеспечить стабильную миграцию, которая будет надежно работать в разных средах.
Если кто-то хочет мигрировать с Retort на Reactions, Pavilion выполняет такие работы вручную на контрактной основе (пишите на contact@pavilion.tech или отправьте мне личное сообщение). Если плагин Reactions будет обновлен для поддержки обобщённых миграций, мы завершим работу по миграции, чтобы сделать её доступной бесплатно.
Ага. Это проясняет некоторые вопросы, которые у меня были. Сложно разобраться в 450 сообщениях за 7 лет.
Так я правильно понимаю, что то, что «нужно» сделать (кто угодно может предложить собственное определение слова «нужно»), — это каким-то образом расширить возможности плагина Reactions, чтобы он мог более аккуратно обрабатывать миграцию данных в него, а также предоставлять функции, которых ему не хватает?
Насколько масштабна эта задача, если предположить в порядке грубой оценки количество часов или долларов?
Это в целом всё ещё верно.

Если возможность создать PR реально существует, я, вероятно, сделаю это просто за хорошую бутылку красного вина. В конце концов, сегодня пятничный вечер.
Но, если быть немного более серьёзным, о чём мы здесь говорим, так это о незначительном рефакторинге плагина Reactions и его класса ReactionManager. Подобная работа обычно не принимается через PR. Для этого потребуется согласие от мейнтейнеров плагина Reactions.
Я думаю, вам также стоит убедиться, что лайки помечаются как silent, а поле created_at корректно обрабатывается для лайков и реакций; в противном случае пользователи будут завалены уведомлениями из-за миграции. (Я столкнулся с этим на своём тестовом сайте при входе в систему.)
По какой-то причине, даже при корректной обработке поля created_by, у меня всё ещё срабатывает ограничение «out of love» для максимального количества лайков, но я не стал углубляться в это, так как устранил все остальные уведомления.
@joffreyjaffeux есть ли причины не предоставить необходимую функциональность для чистой миграции?
Я только что перешел в Reactions (потому что, видимо, это уже официально и всё такое…), но очень не хочу терять все предыдущие данные о возражениях.
Извините, но в настоящее время обеспечить стабильную миграцию невозможно по указанным выше причинам.
Ну что ж, это наконец произошло: я не смог обновить Discourse из-за плагина retort.
Вот ошибка миграции базы данных, которую я получил:
could not create unique index "index_post_details_on_post_id_and_key_ccnew_ccnew" DETAIL: Key (post_id, key)=(30297, +1|retort) is duplicated.
Я использовал этот скрипт как основу для своего собственного кода миграции. Вот что я сделал:
- Чтобы снова запустить Discourse, мне пришлось переопределить параметр “version” в шаблоне .yml, указав коммит примерно двухнедельной давности из репозитория Discourse.
- Пересобрал образ, добавив плагин reactions, чтобы вернуть сайт в строй.
- Настроил плагин reactions с тем же набором реакций, что и у retort. Я не использую ни одной реакции, которую можно было бы интерпретировать как «лайк».
- Немного модифицировал и использовал скрипт от @mcdanlj со следующими шагами (так как я хотел мигрировать все retorts, и у меня уже было соответствие 1-к-1 между retorts и reactions):
- Выполните
./launcher enter app. - Выполните
rails c. - Вставьте следующий код (кажется, что консоль Rails возвращает код с неверными переносами строк; я добавил двойные переносы, но это не сильно изменило вывод. Однако, если у кого-то возникнет ошибка синтаксиса при использовании следующего кода, добавьте дополнительную пустую строку после каждой строки):
def migrateRetortToReactions()
retort = "retort".freeze
emojiType = "emoji".freeze
usermap = Hash.new { |hash, username| hash[username] = User.find_by_username(username) }
postmap = Hash.new { |hash, post_id| hash[post_id] = Post.find(post_id) }
likeType = PostActionType.where(name_key: "like").pluck(:id).first
PostDetail.where(extra: retort).each do |pd|
begin
p = postmap[pd.post_id]
rescue
# PostDetail не согласован относительно удаления
$stderr.puts sprintf("Could not find post for %d: %s / %s", pd.post_id, pd.key, pd.value)
next
end
emoji = pd.key.split('|').first
users = JSON.parse(pd.value)
users.each do |user|
u = usermap[user]
next if u.nil? # изменилось имя пользователя или он был удалён, оставив сиротские Retorts
e = emoji
r = DiscourseReactions::Reaction.where(post_id: p.id, reaction_type: emojiType, reaction_value: e).first_or_create
ru = DiscourseReactions::ReactionUser.where(user_id: u.id, post_id: p.id).first
next unless ru.nil?
$stderr.puts sprintf("Converting Retort %s to Reaction %s for user %s in %s", emoji, e, user, p.url)
DiscourseReactions::ReactionUser.create(reaction_id: r.id, user_id: u.id, post_id: p.id, created_at: pd.created_at)
end
end
end
- На этом этапе я сделал резервную копию сайта на всякий случай.
- Затем выполнил
migrateRetortToReactions, что должно занять некоторое время. У меня не возникло никаких проблем. После выполнения в консоли отображаются все изменённые объекты, поэтому нажмитеq, чтобы выйти. - Теперь на сайте данные должны быть мигрированы корректно.
- В качестве последнего шага необходимо выполнить:
PostDetail.where(extra: "retort").destroy_all, что удалит все данные retort. - После этого я смог пересобрать свой сайт с последней версией Discourse и без плагина retort.
В целом, миграция не так уж сложна, но была довольно пугающей. Как уже обсуждалось ранее, это перезаписывает лайки реакциями на постах, где один и тот же пользователь оставил и лайки, и retorts.
Согласен! Множественные реакции и возможность выбирать из всех реакций — это must-have для моего сообщества. Люди привыкли к этому в мире Discord-чатов, поэтому отказываться от этой функции в моем сообществе нельзя. К счастью, этот плагин пока не сломался у меня, но я смирился с тем, что медленно считаю дни. Надеюсь, что желаемое решение придет либо от сообщества сторонних разработчиков, либо официально от Discourse в ближайшие шесть месяцев. В противном случае мне придется бесконечно держать свой форум на старой версии сборки, если окажется, что этот плагин сломает обновления в будущем.
С новыми изменениями в Ember 5 Retort больше не работает. Изучаем варианты сохранения его функциональности.