From 8f2b002203a01c0a6c4e90521aa20423c7679acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= <regis@hanol.fr> Date: Fri, 16 Oct 2015 17:18:22 +0200 Subject: [PATCH] FIX: a poll option cannot be voted more than 100% of the time --- .../20151016163051_merge_polls_votes.rb | 20 ++++++++++ plugins/poll/plugin.rb | 38 +++++++++---------- 2 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 plugins/poll/db/migrate/20151016163051_merge_polls_votes.rb diff --git a/plugins/poll/db/migrate/20151016163051_merge_polls_votes.rb b/plugins/poll/db/migrate/20151016163051_merge_polls_votes.rb new file mode 100644 index 00000000000..09db8648501 --- /dev/null +++ b/plugins/poll/db/migrate/20151016163051_merge_polls_votes.rb @@ -0,0 +1,20 @@ +class MergePollsVotes < ActiveRecord::Migration + + def up + PostCustomField.where(name: "polls").order(:post_id).pluck(:post_id).each do |post_id| + polls_votes = {} + PostCustomField.where(post_id: post_id).where("name LIKE 'polls-votes-%'").find_each do |pcf| + user_id = pcf.name["polls-votes-".size..-1] + polls_votes["#{user_id}"] = ::JSON.parse(pcf.value) + end + + pcf = PostCustomField.find_or_create_by(name: "polls-votes", post_id: post_id) + pcf.value = ::JSON.parse(pcf.value).merge(polls_votes).to_json + pcf.save + end + end + + def down + end + +end diff --git a/plugins/poll/plugin.rb b/plugins/poll/plugin.rb index a8589f2666d..3f789922da8 100644 --- a/plugins/poll/plugin.rb +++ b/plugins/poll/plugin.rb @@ -66,21 +66,18 @@ after_initialize do raise StandardError.new I18n.t("poll.requires_at_least_1_valid_option") if options.empty? - votes = post.custom_fields["#{VOTES_CUSTOM_FIELD}-#{user_id}"] || {} - vote = votes[poll_name] || [] + post.custom_fields[VOTES_CUSTOM_FIELD] ||= {} + post.custom_fields[VOTES_CUSTOM_FIELD]["#{user_id}"] ||= {} + post.custom_fields[VOTES_CUSTOM_FIELD]["#{user_id}"][poll_name] = options - # increment counters only when the user hasn't casted a vote yet - poll["voters"] += 1 if vote.size == 0 + votes = post.custom_fields[VOTES_CUSTOM_FIELD] + poll["voters"] = votes.values.count { |v| v.has_key?(poll_name) } - poll["options"].each do |option| - option["votes"] -= 1 if vote.include?(option["id"]) - option["votes"] += 1 if options.include?(option["id"]) - end - - votes[poll_name] = options + all_options = Hash.new(0) + votes.map { |_, v| v[poll_name] }.flatten.each { |o| all_options[o] += 1 } + poll["options"].each { |option| option["votes"] = all_options[option["id"]] } post.custom_fields[POLLS_CUSTOM_FIELD] = polls - post.custom_fields["#{VOTES_CUSTOM_FIELD}-#{user_id}"] = votes post.save_custom_fields(true) MessageBus.publish("/polls/#{post_id}", { polls: polls }) @@ -325,9 +322,7 @@ after_initialize do # when the # of options has changed, reset all the votes if polls[poll_name]["options"].size != previous_polls[poll_name]["options"].size - PostCustomField.where(post_id: post.id) - .where("name LIKE '#{VOTES_CUSTOM_FIELD}-%'") - .destroy_all + PostCustomField.where(post_id: post.id, name: VOTES_CUSTOM_FIELD).destroy_all post.clear_custom_fields next end @@ -354,12 +349,10 @@ after_initialize do end Post.register_custom_field_type(POLLS_CUSTOM_FIELD, :json) - Post.register_custom_field_type("#{VOTES_CUSTOM_FIELD}-*", :json) + Post.register_custom_field_type(VOTES_CUSTOM_FIELD, :json) TopicView.add_post_custom_fields_whitelister do |user| - whitelisted = [POLLS_CUSTOM_FIELD] - whitelisted << "#{VOTES_CUSTOM_FIELD}-#{user.id}" if user - whitelisted + user ? [POLLS_CUSTOM_FIELD, VOTES_CUSTOM_FIELD] : [POLLS_CUSTOM_FIELD] end # tells the front-end we have a poll for that post @@ -371,6 +364,11 @@ after_initialize do add_to_serializer(:post, :polls, false) { post_custom_fields[POLLS_CUSTOM_FIELD] } add_to_serializer(:post, :include_polls?) { post_custom_fields.present? && post_custom_fields[POLLS_CUSTOM_FIELD].present? } - add_to_serializer(:post, :polls_votes, false) { post_custom_fields["#{VOTES_CUSTOM_FIELD}-#{scope.user.id}"] } - add_to_serializer(:post, :include_polls_votes?) { scope.user && post_custom_fields.present? && post_custom_fields["#{VOTES_CUSTOM_FIELD}-#{scope.user.id}"].present? } + add_to_serializer(:post, :polls_votes, false) { post_custom_fields[VOTES_CUSTOM_FIELD]["#{scope.user.id}"] } + add_to_serializer(:post, :include_polls_votes?) do + return unless scope.user + return unless post_custom_fields.present? + return unless post_custom_fields[VOTES_CUSTOM_FIELD].present? + post_custom_fields[VOTES_CUSTOM_FIELD].has_key?("#{scope.user.id}") + end end