Discourse Retort

Я создал новый запрос Support multiple-reactions per post (Retort style) о поддержке нескольких реакций на пост в стиле «возражение», поскольку другая ссылка предназначена только для предложения большего выбора реакций к единственной реакции, которую позволяет Discourse Reactions.

3 лайка

Плагин Retort не является #официальным, поэтому мы не можем влиять на то, когда сообщество прекратит его активную разработку и поддержку. :man_shrugging: Всё, что мы можем сделать, — это по возможности информировать людей, чтобы у них было время найти альтернативу (или хотя бы предупредить участников, чтобы смягчить разочарование).

Надеюсь, что эти два #запроса на новые функции когда-нибудь будут реализованы в плагине reactions, но пока они находятся на стадии «хорошие идеи». Но я держу за них кулачки. :crossed_fingers:

3 лайка

Я понимаю вашу позицию. Реальность такова, что ни я, ни Джеймс уже какое-то время не можем уделять достаточно времени полноценной поддержке Retort. Вы заметите, что последний коммит в репозитории был сделан более года назад (мной 21 июля 2021 года). Отлично, что плагин продолжал работать так долго — это свидетельство качества работы, вложенной Джеймсом при его создании.

Когда я говорю, что у меня нет времени, поверьте, я бы очень хотел его иметь! Мне каждый раз грустно, когда приходится принимать такие решения (как, например, с плагином Landing Pages). Я не создавал Retort, но потратил на него немало времени. Когда вы решаете отказаться от чего-то, это похоже на признание того, что то, что вы создали или любили, с чем проводили много часов, дней и недель своей жизни, должно умереть. Я знаю, что для Джеймса это было трудное решение, когда он понял, что должен двигаться дальше.

В отличие от этого, плагин Reactions поддерживается организацией Discourse.org, состоящей из более чем 60 человек, на постоянной основе. Он используется на ряде серверов клиентов Discourse.org. Да, у него пока нет тех же функций, что и у Retort, но я настоятельно рекомендую вам pursue разработку этой функции как направление для развития. Возможно, вы сможете убедить кого-то вроде меня или другого участника Pavilion внести недостающую функцию в плагин через PR. Это был бы разумный путь к достижению ваших долгосрочных целей.

7 лайков

Всегда есть Marketplace, если вы хотите заплатить разработчику, чтобы он возродил проект в это время. Но вам, возможно, придется делать это несколько раз или согласиться на договор о техническом обслуживании.

2 лайка

Полагаю, ответ — нет? Мне бы хотелось перейти на реакции и попытаться найти популярные из них…

1 лайк

Предполагаю, что это возможно, так как они где-то хранятся в базе данных. К сожалению, у меня нет этого плагина, установленного на тестовом сайте, чтобы проверить детали. Существует ли таблица discourse-retort-retorts или аналогичная?

2 лайка

Вот как получить строку, разделенную символом |, для используемых вами ретортов:

# ./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(': :') + ':'

Для меня сейчас это такой набор:

: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:

Чтобы получить маркированный список эмодзи с количеством вхождений каждого:

retorts.keys.sort.each do |k|
  puts "* :#{k}: #{retorts[k].length}"
end

Я не буду вставлять весь маркированный список эмодзи, но он начинается так:

  • :+1: 161
  • :-1: 1
  • :100: 1
  • :arrow_right_hook: 1
  • :astonished: 9
  • :blush: 2
  • :boom: 2
  • :brain: 23
  • :bulb: 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 просто перестанет работать; если я реализую миграцию, я планирую задокументировать это здесь. Но хотя бы знание того, что у вас есть, может вам помочь.

6 лайков

При написании экспериментального кода для миграции 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/ и запустить.

2 лайка

Всем привет, как мы обсуждали в теме выше, я уже написал функцию миграции с Retort на Reactions, включая административный интерфейс.

Чтобы это решение было готово к использованию в production, разработчикам плагина Reactions потребуется внести небольшое изменение для улучшения абстракции кода в плагине Reactions.

Поддержка миграции на уровне production между двумя плагинами требует значительного обеспечения качества, иначе могут легко возникнуть проблемы, подобные этой.

4 лайка

Извините! Я пропустил эти посты и просто посмотрел в основной ветке. Это длинная тема…

Я согласен. Я полностью обошел этот вопрос. Дело не только в ReactionManager.toggle! — ведь действительно нужно передавать created_at, верно?

Переход на Reactions действительно меняет семантику функции «лайк», потому что нельзя отменить действие, если кто-то отредактирует свой пост. Я бы не сделал такой же выбор в реализации. :frowning:

В любом случае, то, что я хочу сделать, — это управлять этим через скрипт, и у меня нет никакого интереса управлять этим через интерфейс. Я не целевая аудитория для UI, так что, возможно, наличие моего хака не повредит.

1 лайк

Разумеется, я не хотел отговаривать вас от написания этого для собственных нужд, но я бы не рекомендовал другим сайтам использовать это, если они не знакомы с кодом и структурой данных.

Суть в том, что плагин Reactions в настоящее время написан не так, чтобы обеспечить стабильную миграцию, которая будет надежно работать в разных средах.

Если кто-то хочет мигрировать с Retort на Reactions, Pavilion выполняет такие работы вручную на контрактной основе (пишите на contact@pavilion.tech или отправьте мне личное сообщение). Если плагин Reactions будет обновлен для поддержки обобщённых миграций, мы завершим работу по миграции, чтобы сделать её доступной бесплатно.

2 лайка

Ага. Это проясняет некоторые вопросы, которые у меня были. Сложно разобраться в 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.

6 лайков

Согласен! Множественные реакции и возможность выбирать из всех реакций — это must-have для моего сообщества. Люди привыкли к этому в мире Discord-чатов, поэтому отказываться от этой функции в моем сообществе нельзя. К счастью, этот плагин пока не сломался у меня, но я смирился с тем, что медленно считаю дни. Надеюсь, что желаемое решение придет либо от сообщества сторонних разработчиков, либо официально от Discourse в ближайшие шесть месяцев. В противном случае мне придется бесконечно держать свой форум на старой версии сборки, если окажется, что этот плагин сломает обновления в будущем.

1 лайк

С новыми изменениями в Ember 5 Retort больше не работает. Изучаем варианты сохранения его функциональности.

1 лайк