FEATURE: Show votes in an "on voted" poll to the creator

This required properly plumbing the guardian into the serializer.

Notably, the default state in the client was not changed - if you haven't voted in
the poll, you need to click the button to view the results instead of the results
being immediately visible on page load.

Implements https://meta.discourse.org/t/-/138108
This commit is contained in:
Kane York 2020-03-20 11:29:00 -07:00 committed by Kane York
parent 0d3386d255
commit 330102fd20
6 changed files with 30 additions and 11 deletions

View File

@ -47,7 +47,11 @@ class Poll < ActiveRecord::Base
def can_see_results?(user) def can_see_results?(user)
return !!user&.staff? if staff_only? return !!user&.staff? if staff_only?
!!(always? || (on_vote? && has_voted?(user)) || is_closed?) !!(always? || (on_vote? && (is_me?(user) || has_voted?(user))) || is_closed?)
end
def is_me?(user)
user && post.user&.id == user&.id
end end
def has_voted?(user) def has_voted?(user)

View File

@ -61,7 +61,7 @@ class PollSerializer < ApplicationSerializer
end end
def include_preloaded_voters? def include_preloaded_voters?
object.can_see_voters?(scope) object.can_see_voters?(scope.user)
end end
end end

View File

@ -678,6 +678,7 @@ createWidget("discourse-poll-buttons", {
const staffOnly = poll.results === "staff_only"; const staffOnly = poll.results === "staff_only";
const isStaff = this.currentUser && this.currentUser.staff; const isStaff = this.currentUser && this.currentUser.staff;
const isAdmin = this.currentUser && this.currentUser.admin; const isAdmin = this.currentUser && this.currentUser.admin;
const isMe = this.currentUser && post.user_id === this.currentUser.id;
const dataExplorerEnabled = this.siteSettings.data_explorer_enabled; const dataExplorerEnabled = this.siteSettings.data_explorer_enabled;
const hideResultsDisabled = !staffOnly && (closed || topicArchived); const hideResultsDisabled = !staffOnly && (closed || topicArchived);
const exportQueryID = this.siteSettings.poll_export_data_explorer_query_id; const exportQueryID = this.siteSettings.poll_export_data_explorer_query_id;
@ -710,7 +711,7 @@ createWidget("discourse-poll-buttons", {
}) })
); );
} else { } else {
if (poll.get("results") === "on_vote" && !attrs.hasVoted) { if (poll.get("results") === "on_vote" && !attrs.hasVoted && !isMe) {
contents.push(infoTextHtml(I18n.t("poll.results.vote.title"))); contents.push(infoTextHtml(I18n.t("poll.results.vote.title")));
} else if (poll.get("results") === "on_close" && !closed) { } else if (poll.get("results") === "on_close" && !closed) {
contents.push(infoTextHtml(I18n.t("poll.results.closed.title"))); contents.push(infoTextHtml(I18n.t("poll.results.closed.title")));

View File

@ -93,7 +93,7 @@ module DiscoursePoll
if has_changed if has_changed
polls = ::Poll.includes(poll_options: :poll_votes).where(post: post) polls = ::Poll.includes(poll_options: :poll_votes).where(post: post)
polls = ActiveModel::ArraySerializer.new(polls, each_serializer: PollSerializer, root: false).as_json polls = ActiveModel::ArraySerializer.new(polls, each_serializer: PollSerializer, root: false, scope: Guardian.new(nil)).as_json
post.publish_message!("/polls/#{post.topic_id}", post_id: post.id, polls: polls) post.publish_message!("/polls/#{post.topic_id}", post_id: post.id, polls: polls)
end end
end end

View File

@ -62,7 +62,8 @@ after_initialize do
end end
# user must be allowed to post in topic # user must be allowed to post in topic
if !Guardian.new(user).can_create_post?(post.topic) guardian = Guardian.new(user)
if !guardian.can_create_post?(post.topic)
raise StandardError.new I18n.t("poll.user_cant_post_in_topic") raise StandardError.new I18n.t("poll.user_cant_post_in_topic")
end end
@ -108,7 +109,7 @@ after_initialize do
poll.reload poll.reload
serialized_poll = PollSerializer.new(poll, root: false).as_json serialized_poll = PollSerializer.new(poll, root: false, scope: guardian).as_json
payload = { post_id: post_id, polls: [serialized_poll] } payload = { post_id: post_id, polls: [serialized_poll] }
post.publish_message!("/polls/#{post.topic_id}", payload) post.publish_message!("/polls/#{post.topic_id}", payload)
@ -120,6 +121,7 @@ after_initialize do
def toggle_status(post_id, poll_name, status, user, raise_errors = true) def toggle_status(post_id, poll_name, status, user, raise_errors = true)
Poll.transaction do Poll.transaction do
post = Post.find_by(id: post_id) post = Post.find_by(id: post_id)
guardian = Guardian.new(user)
# post must not be deleted # post must not be deleted
if post.nil? || post.trashed? if post.nil? || post.trashed?
@ -149,7 +151,7 @@ after_initialize do
poll.status = status poll.status = status
poll.save! poll.save!
serialized_poll = PollSerializer.new(poll, root: false).as_json serialized_poll = PollSerializer.new(poll, root: false, scope: guardian).as_json
payload = { post_id: post_id, polls: [serialized_poll] } payload = { post_id: post_id, polls: [serialized_poll] }
post.publish_message!("/polls/#{post.topic_id}", payload) post.publish_message!("/polls/#{post.topic_id}", payload)
@ -542,11 +544,12 @@ after_initialize do
end end
end end
on(:post_created) do |post| on(:post_created) do |post, _opts, user|
guardian = Guardian.new(user)
DiscoursePoll::Poll.schedule_jobs(post) DiscoursePoll::Poll.schedule_jobs(post)
unless post.is_first_post? unless post.is_first_post?
polls = ActiveModel::ArraySerializer.new(post.polls, each_serializer: PollSerializer, root: false).as_json polls = ActiveModel::ArraySerializer.new(post.polls, each_serializer: PollSerializer, root: false, scope: guardian).as_json
post.publish_message!("/polls/#{post.topic_id}", post_id: post.id, polls: polls) post.publish_message!("/polls/#{post.topic_id}", post_id: post.id, polls: polls)
end end
end end
@ -594,7 +597,7 @@ after_initialize do
end end
add_to_serializer(:post, :polls, false) do add_to_serializer(:post, :polls, false) do
preloaded_polls.map { |p| PollSerializer.new(p, root: false) } preloaded_polls.map { |p| PollSerializer.new(p, root: false, scope: self.scope) }
end end
add_to_serializer(:post, :include_polls?) do add_to_serializer(:post, :include_polls?) do

View File

@ -31,10 +31,21 @@ describe ::DiscoursePoll::Poll do
option = poll.poll_options.first option = poll.poll_options.first
expect(poll.can_see_results?(user)).to eq(false) expect(poll.can_see_results?(user)).to eq(false)
poll.poll_votes.create!(poll_option_id: option.id , user_id: user.id) poll.poll_votes.create!(poll_option_id: option.id, user_id: user.id)
expect(poll.can_see_results?(user)).to eq(true) expect(poll.can_see_results?(user)).to eq(true)
end end
it "author can see results when results setting is on_vote" do
author = Fabricate(:user)
post = Fabricate(:post, user: author, raw: "[poll results=on_vote]\n- A\n- B\n[/poll]")
poll = post.polls.first
option = poll.poll_options.first
expect(poll.can_see_results?(author)).to eq(true)
poll.poll_votes.create!(poll_option_id: option.id, user_id: author.id)
expect(poll.can_see_results?(author)).to eq(true)
end
it "everyone can see results when results setting is on_vote and poll is closed" do it "everyone can see results when results setting is on_vote and poll is closed" do
post = Fabricate(:post, raw: "[poll results=on_vote]\n- A\n- B\n[/poll]") post = Fabricate(:post, raw: "[poll results=on_vote]\n- A\n- B\n[/poll]")
user = Fabricate(:user) user = Fabricate(:user)