From 74ca49d7cdad36d995c0687313b8179ade1aeb78 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Mon, 6 May 2019 12:37:19 +0200 Subject: [PATCH] FIX: Importing of polls from phpBB3 was broken Follow-up to 24369a81 --- .prettierignore | 1 + .../phpbb3/importers/poll_importer.rb | 162 ++++++++---------- .../phpbb3/importers/post_importer.rb | 14 +- script/import_scripts/phpbb3/settings.yml | 2 +- 4 files changed, 85 insertions(+), 94 deletions(-) diff --git a/.prettierignore b/.prettierignore index 62137720c88..a7c0bf8148f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,4 @@ plugins/**/assets/stylesheets/vendor/ package.json config/locales/**/*.yml !config/locales/**/*.en.yml +script/import_scripts/**/*.yml diff --git a/script/import_scripts/phpbb3/importers/poll_importer.rb b/script/import_scripts/phpbb3/importers/poll_importer.rb index 261e46b43d2..3349f054eb5 100644 --- a/script/import_scripts/phpbb3/importers/poll_importer.rb +++ b/script/import_scripts/phpbb3/importers/poll_importer.rb @@ -9,26 +9,19 @@ module ImportScripts::PhpBB3 @text_processor = text_processor end - # @param poll [ImportScripts::PhpBB3::Poll] - def map_poll(topic_id, poll) - options = get_poll_options(topic_id) - poll_text = get_poll_text(options, poll) - extracted_poll = extract_default_poll(topic_id, poll_text) + # @param poll_data [ImportScripts::PhpBB3::PollData] + def create_raw(topic_id, poll_data) + poll_data.options = get_poll_options(topic_id) + get_poll_text(poll_data) + end - return if extracted_poll.nil? - - update_poll_metadata(extracted_poll, topic_id, poll) - update_poll_options(extracted_poll, options, poll) - - mapped_poll = { - raw: poll_text, - custom_fields: {} - } - - add_poll_to_custom_fields(mapped_poll[:custom_fields], extracted_poll) - add_votes_to_custom_fields(mapped_poll[:custom_fields], topic_id, poll) - - mapped_poll + # @param post [Post] + # @param poll_data [ImportScripts::PhpBB3::PollData] + def update_poll(topic_id, post, poll_data) + if poll = post.polls.first + update_anonymous_voters(topic_id, poll_data, poll) + create_votes(topic_id, poll_data, poll) + end end protected @@ -38,7 +31,7 @@ module ImportScripts::PhpBB3 options_by_text = Hash.new { |h, k| h[k] = { ids: [], total_votes: 0, anonymous_votes: 0 } } rows.each do |row| - option_text = @text_processor.process_raw_text(row[:poll_option_text]).delete("\n") + option_text = get_option_text(row) # phpBB allows duplicate options (why?!) - we need to merge them option = options_by_text[option_text] @@ -51,100 +44,97 @@ module ImportScripts::PhpBB3 options_by_text.values end - # @param options [Array] - # @param poll [ImportScripts::PhpBB3::Poll] - def get_poll_text(options, poll) - poll_text = "#{poll.title}\n" + def get_option_text(row) + text = @text_processor.process_raw_text(row[:poll_option_text]) + text.squish! + text.gsub!(/^(\d+)\./, '\1\.') + text + end - if poll.max_options > 1 - poll_text << "[poll type=multiple max=#{poll.max_options}]" + # @param poll_data [ImportScripts::PhpBB3::PollData] + def get_poll_text(poll_data) + title = @text_processor.process_raw_text(poll_data.title) + text = "#{title}\n\n" + + arguments = ["results=always"] + arguments << "close=#{poll_data.close_time.iso8601}" if poll_data.close_time + + if poll_data.max_options > 1 + arguments << "type=multiple" << "max=#{poll_data.max_options}" else - poll_text << '[poll]' + arguments << "type=regular" end - options.each do |option| - poll_text << "\n- #{option[:text]}" + text << "[poll #{arguments.join(' ')}]" + + poll_data.options.each do |option| + text << "\n* #{option[:text]}" end - poll_text << "\n[/poll]" + text << "\n[/poll]" end - def extract_default_poll(topic_id, poll_text) - extracted_polls = DiscoursePoll::Poll::extract(poll_text, topic_id) - extracted_polls.each do |poll| - return poll if poll['name'] == DiscoursePoll::DEFAULT_POLL_NAME - end - - puts "Failed to extract poll for topic id #{topic_id}. The poll text is:" - puts poll_text - end - - # @param poll [ImportScripts::PhpBB3::Poll] - def update_poll_metadata(extracted_poll, topic_id, poll) + # @param poll_data [ImportScripts::PhpBB3::PollData] + # @param poll [Poll] + def update_anonymous_voters(topic_id, poll_data, poll) row = @database.get_voters(topic_id) - extracted_poll['voters'] = row[:total_voters] - extracted_poll['anonymous_voters'] = row[:anonymous_voters] if row[:anonymous_voters] > 0 - extracted_poll['status'] = poll.has_ended? ? :open : :closed - end + if row[:anonymous_voters] > 0 + poll.update!(anonymous_voters: row[:anonymous_voters]) - # @param poll [ImportScripts::PhpBB3::Poll] - def update_poll_options(extracted_poll, imported_options, poll) - extracted_poll['options'].each_with_index do |option, index| - imported_option = imported_options[index] - option['votes'] = imported_option[:total_votes] - option['anonymous_votes'] = imported_option[:anonymous_votes] if imported_option[:anonymous_votes] > 0 - poll.add_option_id(imported_option[:ids], option['id']) + poll.poll_options.each_with_index do |option, index| + imported_option = poll_data.options[index] + + if imported_option[:anonymous_votes] > 0 + option.update!(anonymous_votes: imported_option[:anonymous_votes]) + end + end end end - # @param custom_fields [Hash] - def add_poll_to_custom_fields(custom_fields, extracted_poll) - custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD] = { DiscoursePoll::DEFAULT_POLL_NAME => extracted_poll } - end + # @param poll_data [ImportScripts::PhpBB3::PollData] + # @param poll [Poll] + def map_poll_options(poll_data, poll) + option_ids = {} - # @param custom_fields [Hash] - # @param poll [ImportScripts::PhpBB3::Poll] - def add_votes_to_custom_fields(custom_fields, topic_id, poll) - rows = @database.fetch_poll_votes(topic_id) - votes = {} + poll.poll_options.each_with_index do |option, index| + imported_option = poll_data.options[index] - rows.each do |row| - option_id = poll.option_id_from_imported_option_id(row[:poll_option_id]) - user_id = @lookup.user_id_from_imported_user_id(row[:user_id]) - - if option_id.present? && user_id.present? - user_votes = votes["#{user_id}"] ||= {} - user_votes = user_votes[DiscoursePoll::DEFAULT_POLL_NAME] ||= [] - user_votes << option_id + imported_option[:ids].each do |imported_id| + option_ids[imported_id] = option.id end end - custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD] = votes + option_ids + end + + # @param poll_data [ImportScripts::PhpBB3::PollData] + # @param poll [Poll] + def create_votes(topic_id, poll_data, poll) + mapped_option_ids = map_poll_options(poll_data, poll) + rows = @database.fetch_poll_votes(topic_id) + + rows.each do |row| + option_id = mapped_option_ids[row[:poll_option_id]] + user_id = @lookup.user_id_from_imported_user_id(row[:user_id]) + + if option_id.present? && user_id.present? + PollVote.create!(poll: poll, poll_option_id: option_id, user_id: user_id) + end + end end end - class Poll + class PollData attr_reader :title attr_reader :max_options + attr_reader :close_time + attr_accessor :options def initialize(title, max_options, end_timestamp) @title = title @max_options = max_options - @end_timestamp = end_timestamp - @option_ids = {} - end - - def has_ended? - @end_timestamp.nil? || Time.zone.at(@end_timestamp) > Time.now - end - - def add_option_id(imported_ids, option_id) - imported_ids.each { |imported_id| @option_ids[imported_id] = option_id } - end - - def option_id_from_imported_option_id(imported_id) - @option_ids[imported_id] + @close_time = Time.zone.at(end_timestamp) if end_timestamp end end end diff --git a/script/import_scripts/phpbb3/importers/post_importer.rb b/script/import_scripts/phpbb3/importers/post_importer.rb index edaf1ccab4b..b184bcaa31c 100644 --- a/script/import_scripts/phpbb3/importers/post_importer.rb +++ b/script/import_scripts/phpbb3/importers/post_importer.rb @@ -50,6 +50,8 @@ module ImportScripts::PhpBB3 end def map_first_post(row, mapped) + poll_data = add_poll(row, mapped) if @settings.import_polls + mapped[:category] = @lookup.category_id_from_imported_category_id(row[:forum_id]) mapped[:title] = CGI.unescapeHTML(row[:topic_title]).strip[0...255] mapped[:pinned_at] = mapped[:created_at] unless row[:topic_type] == Constants::POST_NORMAL @@ -58,10 +60,10 @@ module ImportScripts::PhpBB3 mapped[:post_create_action] = proc do |post| @permalink_importer.create_for_topic(post.topic, row[:topic_id]) @permalink_importer.create_for_post(post, row[:post_id]) + @poll_importer.update_poll(row[:topic_id], post, poll_data) if poll_data TopicViewItem.add(post.topic_id, row[:poster_ip], post.user_id, post.created_at, true) end - add_poll(row, mapped) if @settings.import_polls mapped end @@ -85,13 +87,11 @@ module ImportScripts::PhpBB3 def add_poll(row, mapped_post) return if row[:poll_title].blank? - poll = Poll.new(row[:poll_title], row[:poll_max_options], row[:poll_end]) - mapped_poll = @poll_importer.map_poll(row[:topic_id], poll) + poll_data = PollData.new(row[:poll_title], row[:poll_max_options], row[:poll_end]) + poll_raw = @poll_importer.create_raw(row[:topic_id], poll_data) - if mapped_poll.present? - mapped_post[:raw] = mapped_poll[:raw] << "\n" << mapped_post[:raw] - mapped_post[:custom_fields] = mapped_poll[:custom_fields] - end + mapped_post[:raw] = poll_raw << "\n\n" << mapped_post[:raw] + poll_data end end end diff --git a/script/import_scripts/phpbb3/settings.yml b/script/import_scripts/phpbb3/settings.yml index 9a4b6a98a65..e884dfc12fd 100644 --- a/script/import_scripts/phpbb3/settings.yml +++ b/script/import_scripts/phpbb3/settings.yml @@ -53,7 +53,7 @@ import: bookmarks: true attachments: true private_messages: true - polls: false # Don't set this to true. Importing polls is currently broken. + polls: true # When true: each imported user will have the original username from phpBB as its name # When false: the name of each imported user will be blank unless the username was changed during import