diff --git a/lib/tasks/consul.rake b/lib/tasks/consul.rake index 9f56f3c38..0e89a360f 100644 --- a/lib/tasks/consul.rake +++ b/lib/tasks/consul.rake @@ -8,6 +8,7 @@ namespace :consul do desc "Runs tasks needed to upgrade from 2.1.1 to 2.2.0" task "execute_release_2.2.0_tasks": [ "db:mask_ips", - "polls:remove_duplicate_voters" + "polls:remove_duplicate_voters", + "polls:remove_duplicate_answers" ] end diff --git a/lib/tasks/polls.rake b/lib/tasks/polls.rake index b6040a127..bda3058eb 100644 --- a/lib/tasks/polls.rake +++ b/lib/tasks/polls.rake @@ -28,4 +28,37 @@ namespace :polls do end end end + + desc "Removes duplicate poll answers" + task remove_duplicate_answers: :environment do + logger = ApplicationLogger.new + duplicate_records_logger = DuplicateRecordsLogger.new + + logger.info "Removing duplicate answers in polls" + + Tenant.run_on_each do + duplicate_ids = Poll::Answer.where(option_id: nil) + .select(:question_id, :author_id, :answer) + .group(:question_id, :author_id, :answer) + .having("count(*) > 1") + .pluck(:question_id, :author_id, :answer) + + duplicate_ids.each do |question_id, author_id, answer| + poll_answers = Poll::Answer.where(question_id: question_id, author_id: author_id, answer: answer) + + poll_answers.excluding(poll_answers.first).each do |poll_answer| + poll_answer.delete + + tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default? + log_message = "Deleted duplicate record with ID #{poll_answer.id} " \ + "from the #{Poll::Answer.table_name} table " \ + "with question_id #{question_id}, " \ + "author_id #{author_id} " \ + "and answer #{answer}" + tenant_info.to_s + logger.info(log_message) + duplicate_records_logger.info(log_message) + end + end + end + end end diff --git a/spec/factories/polls.rb b/spec/factories/polls.rb index 4e07dc5f5..735c20cb8 100644 --- a/spec/factories/polls.rb +++ b/spec/factories/polls.rb @@ -73,6 +73,14 @@ FactoryBot.define do end end + trait :abcde do + after(:create) do |question| + %w[A B C D E].each do |letter| + create(:poll_question_option, question: question, title: "Answer #{letter}") + end + end + end + factory :poll_question_unique do after(:create) do |question| create(:votation_type_unique, questionable: question) diff --git a/spec/lib/tasks/polls_spec.rb b/spec/lib/tasks/polls_spec.rb index 2b43c969d..da5050564 100644 --- a/spec/lib/tasks/polls_spec.rb +++ b/spec/lib/tasks/polls_spec.rb @@ -46,4 +46,78 @@ describe "polls tasks" do end end end + + describe "polls:remove_duplicate_answers" do + before { Rake::Task["polls:remove_duplicate_answers"].reenable } + + it "removes duplicate answers" do + question = create(:poll_question_multiple, :abcde, poll: poll, max_votes: 4) + abc_question = create(:poll_question_multiple, :abc, poll: poll) + + answer_attributes = { + question_id: question.id, + author_id: user.id, + answer: "Answer A", + option_id: nil + } + abc_answer_attributes = answer_attributes.merge(question_id: abc_question.id, answer: "Answer B") + + answer = create(:poll_answer, answer_attributes) + other_answer = create(:poll_answer, answer_attributes.merge(answer: "Answer B")) + other_user_answer = create(:poll_answer, answer_attributes.merge(author_id: create(:user).id)) + abc_answer = create(:poll_answer, abc_answer_attributes) + + 2.times { insert(:poll_answer, answer_attributes) } + insert(:poll_answer, abc_answer_attributes) + + expect(Poll::Answer.count).to eq 7 + + Rake.application.invoke_task("polls:remove_duplicate_answers") + + expect(Poll::Answer.count).to eq 4 + expect(Poll::Answer.all).to match_array [answer, other_answer, other_user_answer, abc_answer] + end + + it "does not remove answers with the same text and different options" do + question = create(:poll_question_multiple, :abcde, max_votes: 4) + option_a = question.question_options.find_by(title: "Answer A") + option_b = question.question_options.find_by(title: "Answer B") + + answer_attributes = { question: question, author: user, answer: "Answer A" } + create(:poll_answer, answer_attributes.merge(option: option_a)) + create(:poll_answer, answer_attributes.merge(option: option_b)) + + expect(Poll::Answer.count).to eq 2 + + Rake.application.invoke_task("polls:remove_duplicate_answers") + + expect(Poll::Answer.count).to eq 2 + end + + it "removes duplicate answers on tenants" do + create(:tenant, schema: "answers") + + Tenant.switch("answers") do + user = create(:user, :level_two) + question = create(:poll_question_multiple, :abc) + + answer_attributes = { + question_id: question.id, + author_id: user.id, + answer: "Answer A", + option_id: nil + } + create(:poll_answer, answer_attributes) + insert(:poll_answer, answer_attributes) + + expect(Poll::Answer.count).to eq 2 + end + + Rake.application.invoke_task("polls:remove_duplicate_answers") + + Tenant.switch("answers") do + expect(Poll::Answer.count).to eq 1 + end + end + end end