Adding Import Support for Discourse Reactions Plugin (#30361)

* Adding Import Support for Discourse Reactions Plugin

---------

Co-authored-by: Gerhard Schlager <gerhard.schlager@discourse.org>
This commit is contained in:
Ruben Oussoren 2025-01-07 08:58:26 -05:00 committed by GitHub
parent affe26f0dd
commit 20a16ea231
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 186 additions and 4 deletions

View File

@ -120,6 +120,7 @@ class BulkImport::Base
chat_channel: 6,
chat_thread: 7,
chat_message: 8,
discourse_reactions_reaction: 9,
)
def create_migration_mappings_table
@ -309,6 +310,10 @@ class BulkImport::Base
@chat_message_mapping = load_index(MAPPING_TYPES[:chat_message])
@last_chat_message_id = last_id(Chat::Message)
puts "Loading reaction indexes..."
@discourse_reaction_mapping = load_index(MAPPING_TYPES[:discourse_reactions_reaction])
@last_discourse_reaction_id = last_id(DiscourseReactions::Reaction)
end
def use_bbcode_to_md?
@ -390,6 +395,11 @@ class BulkImport::Base
"SELECT setval('#{Chat::Message.sequence_name}', #{@last_chat_message_id})",
)
end
if @last_discourse_reaction_id > 0
@raw_connection.exec(
"SELECT setval('#{DiscourseReactions::Reaction.sequence_name}', #{@last_discourse_reaction_id})",
)
end
end
def group_id_from_imported_id(id)
@ -475,6 +485,10 @@ class BulkImport::Base
@chat_message_mapping[id.to_s]&.to_i
end
def discourse_reaction_id_from_original_id(id)
@discourse_reaction_mapping[id.to_s]&.to_i
end
GROUP_COLUMNS = %i[
id
name
@ -925,6 +939,18 @@ class BulkImport::Base
CHAT_MENTION_COLUMNS = %i[chat_message_id target_id type created_at updated_at]
REACTION_USER_COLUMNS = %i[reaction_id user_id created_at updated_at post_id]
REACTION_COLUMNS = %i[
id
post_id
reaction_type
reaction_value
reaction_users_count
created_at
updated_at
]
def create_groups(rows, &block)
create_records(rows, "group", GROUP_COLUMNS, &block)
end
@ -1157,6 +1183,14 @@ class BulkImport::Base
create_records(rows, "chat_mention", CHAT_MENTION_COLUMNS, &block)
end
def create_reaction_users(rows, &block)
create_records(rows, "discourse_reactions_reaction_user", REACTION_USER_COLUMNS, &block)
end
def create_reactions(rows, &block)
create_records_with_mapping(rows, "discourse_reactions_reaction", REACTION_COLUMNS, &block)
end
def process_group(group)
@groups[group[:imported_id].to_i] = group[:id] = @last_group_id += 1
@ -1962,6 +1996,24 @@ class BulkImport::Base
mention
end
def process_discourse_reactions_reaction_user(reaction_user)
reaction_user[:created_at] ||= NOW
reaction_user[:updated_at] ||= NOW
reaction_user
end
def process_discourse_reactions_reaction(reaction)
reaction[:id] = @last_discourse_reaction_id += 1
reaction[:created_at] ||= NOW
reaction[:updated_at] ||= NOW
reaction[:reaction_users_count] ||= 0
@imported_records[reaction[:original_id].to_s] = reaction[:id]
@discourse_reaction_mapping[reaction[:original_id].to_s] = reaction[:id]
reaction
end
def create_records(all_rows, name, columns, &block)
start = Time.now
imported_ids = []

View File

@ -126,6 +126,10 @@ class BulkImport::Generic < BulkImport::Base
update_chat_threads
update_chat_membership_metadata
import_reactions
import_reaction_users
import_reaction_shadow_likes
import_upload_references
end
@ -320,16 +324,19 @@ class BulkImport::Generic < BulkImport::Base
puts "", "Importing category permissions..."
permissions = query(<<~SQL)
SELECT c.id AS category_id, p.value -> 'group_id' AS group_id, p.value -> 'permission_type' AS permission_type
FROM categories c,
JSON_EACH(c.permissions) p
SELECT c.id AS category_id,
p.value -> 'group_id' AS group_id,
p.value -> 'existing_group_id' AS existing_group_id,
p.value -> 'permission_type' AS permission_type
FROM categories c,
JSON_EACH(c.permissions) p
SQL
existing_category_group_ids = CategoryGroup.pluck(:category_id, :group_id).to_set
create_category_groups(permissions) do |row|
category_id = category_id_from_imported_id(row["category_id"])
group_id = group_id_from_imported_id(row["group_id"])
group_id = row["existing_group_id"] || group_id_from_imported_id(row["group_id"])
next if existing_category_group_ids.include?([category_id, group_id])
{ category_id: category_id, group_id: group_id, permission_type: row["permission_type"] }
@ -2943,6 +2950,129 @@ class BulkImport::Generic < BulkImport::Base
puts " Update took #{(Time.now - start_time).to_i} seconds."
end
def import_reaction_users
unless defined?(::DiscourseReactions)
puts "",
"Skipping reaction users import, because the Discourse Reactions plugin is not installed."
return
end
puts "", "Importing reaction users..."
reaction_users = query(<<~SQL)
SELECT *
FROM discourse_reactions_reaction_users
ORDER BY post_id, user_id
SQL
existing_reaction_users =
DiscourseReactions::ReactionUser.pluck(:reaction_id, :user_id, :post_id).to_set
create_reaction_users(reaction_users) do |row|
next if row["reaction_id"].blank?
user_id = user_id_from_imported_id(row["user_id"])
post_id = post_id_from_imported_id(row["post_id"])
reaction_id = discourse_reaction_id_from_original_id(row["reaction_id"])
next if post_id.blank? || user_id.blank? || reaction_id.blank?
next unless existing_reaction_users.add?([reaction_id, user_id, post_id])
{
reaction_id:,
user_id:,
created_at: to_datetime(row["created_at"]),
updated_at: to_datetime(row["updated_at"]),
post_id:,
}
end
reaction_users.close
end
def import_reactions
unless defined?(::DiscourseReactions)
puts "", "Skipping reactions import, because the Discourse Reactions plugin is not installed."
return
end
puts "", "Importing reactions..."
reactions = query(<<~SQL)
SELECT *
FROM discourse_reactions_reactions
ORDER BY post_id, reaction_value
SQL
reaction_type_id = DiscourseReactions::Reaction.reaction_types["emoji"]
existing_reactions = DiscourseReactions::Reaction.pluck(:post_id, :reaction_value).to_set
create_reactions(reactions) do |row|
next if row["id"].blank?
post_id = post_id_from_imported_id(row["post_id"])
next if post_id.blank? || row["reaction_value"].blank?
next unless existing_reactions.add?([post_id, row["reaction_value"]])
{
original_id: row["id"],
post_id: post_id,
reaction_type: reaction_type_id,
reaction_value: row["reaction_value"],
reaction_users_count: row["reaction_users_count"],
created_at: to_datetime(row["created_at"]),
updated_at: to_datetime(row["updated_at"]),
}
end
reactions.close
end
def import_reaction_shadow_likes
unless defined?(::DiscourseReactions)
puts "",
"Skipping reaction shadow likes import, because the Discourse Reactions plugin is not installed."
return
end
puts "", "Importing reaction shadow likes..."
reactions = query(<<~SQL)
SELECT u.post_id, u.user_id, r.reaction_value, u.created_at
FROM discourse_reactions_reactions r
JOIN discourse_reactions_reaction_users u ON r.id = u.reaction_id
ORDER BY u.post_id, u.user_id
SQL
post_action_type_id = PostActionType.types[:like]
existing_likes =
PostAction.where(post_action_type_id: post_action_type_id).pluck(:post_id, :user_id).to_set
create_post_actions(reactions) do |row|
next if reaction_excluded_from_like?(row["reaction_value"])
post_id = post_id_from_imported_id(row["post_id"])
user_id = user_id_from_imported_id(row["user_id"])
next unless post_id && user_id
next unless existing_likes.add?([post_id, user_id])
{
post_id: post_id,
user_id: user_id,
post_action_type_id: post_action_type_id,
created_at: to_datetime(row["created_at"]),
}
end
reactions.close
end
def reaction_excluded_from_like?(reaction_value)
DiscourseReactions::Reaction.reactions_excluded_from_like.include?(reaction_value)
end
def calculate_external_url(row)
external_url = row["external_url"].dup
placeholders = row["external_url_placeholders"]&.then { |json| JSON.parse(json) }