Retort - a reaction-style plugin for Discourse

Well, it now happened, I could not update discourse because of the retort plugin.

This is the database migration error I got:

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.

I used this script as a base for my own migration code. Here’s what I did.

  • To get discourse working again, I had to override the “version” in the template .yml file to a commit from about two weeks ago in discourse repo
  • Rebuild with the reactions plugin added to get the site back up
  • I configured the reactions plugin with the same set of reactions as retort. I do not use any reaction that could be interpreted as like
  • I used @mcdanlj’s script a bit modified with the following steps (as I wanted to migrate all retorts and I had 1-to-1 mapping between retorts and reactions already):
  • Run ./launcher enter app
  • Run rails c
  • Paste in the following (it seems that rails console will echo back the code with incorrect line changes, I added double line changes but that didn’t really change the output, but if someone gets a syntax error with the following code, add an extra line after each line):
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 not consistent WRT delete
      $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? # changed user name or deleted user leaves orphaned 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
  • At this point I made a site backup just in case
  • Then run migrateRetortToReactions which should take a while. For me I didn’t see or run into any issues. After running the console seems to show all the changed objects so hit q to exit
  • Now on the site it should be the case that the data is migrated correctly
  • As a final step you need to run: PostDetail.where(extra: "retort").destroy_all which will delete the retort data
  • Now I was able to then rebuild my site with latest discourse version and without the retort plugin

So all in all, not that difficult to migrate but it was pretty scary, and as discussed before this overwrites likes with reactions on posts that had both likes and retorts by the same user.

6 Likes