mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-30 10:58:31 -05:00
FEATURE: Add public type to polls.
This commit is contained in:
parent
7aac5baeed
commit
8ecde35df3
17 changed files with 322 additions and 30 deletions
|
@ -0,0 +1,31 @@
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
import User from 'discourse/models/user';
|
||||||
|
import PollVoters from 'discourse/plugins/poll/components/poll-voters';
|
||||||
|
|
||||||
|
export default PollVoters.extend({
|
||||||
|
@computed("pollsVoters", "poll.options", "showMore", "isExpanded", "numOfVotersToShow")
|
||||||
|
users(pollsVoters, options, showMore, isExpanded, numOfVotersToShow) {
|
||||||
|
var users = [];
|
||||||
|
var voterIds = [];
|
||||||
|
const shouldLimit = showMore && !isExpanded;
|
||||||
|
|
||||||
|
options.forEach(option => {
|
||||||
|
option.voter_ids.forEach(voterId => {
|
||||||
|
if (shouldLimit) {
|
||||||
|
if (!(users.length > numOfVotersToShow - 1)) {
|
||||||
|
users.push(pollsVoters[voterId]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
users.push(pollsVoters[voterId]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return users;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("pollsVoters", "numOfVotersToShow")
|
||||||
|
showMore(pollsVoters, numOfVotersToShow) {
|
||||||
|
return !(Object.keys(pollsVoters).length < numOfVotersToShow);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,23 +1,27 @@
|
||||||
import round from "discourse/lib/round";
|
import round from "discourse/lib/round";
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
export default Em.Component.extend({
|
export default Em.Component.extend({
|
||||||
tagName: "span",
|
tagName: "span",
|
||||||
|
|
||||||
totalScore: function() {
|
@computed("poll.options.@each.{html,votes}")
|
||||||
|
totalScore() {
|
||||||
return _.reduce(this.get("poll.options"), function(total, o) {
|
return _.reduce(this.get("poll.options"), function(total, o) {
|
||||||
const value = parseInt(o.get("html"), 10),
|
const value = parseInt(o.get("html"), 10),
|
||||||
votes = parseInt(o.get("votes"), 10);
|
votes = parseInt(o.get("votes"), 10);
|
||||||
return total + value * votes;
|
return total + value * votes;
|
||||||
}, 0);
|
}, 0);
|
||||||
}.property("poll.options.@each.{html,votes}"),
|
},
|
||||||
|
|
||||||
average: function() {
|
@computed("totalScore", "poll.voters")
|
||||||
|
average() {
|
||||||
const voters = this.get("poll.voters");
|
const voters = this.get("poll.voters");
|
||||||
return voters === 0 ? 0 : round(this.get("totalScore") / voters, -2);
|
return voters === 0 ? 0 : round(this.get("totalScore") / voters, -2);
|
||||||
}.property("totalScore", "poll.voters"),
|
},
|
||||||
|
|
||||||
averageRating: function() {
|
@computed("average")
|
||||||
|
averageRating() {
|
||||||
return I18n.t("poll.average_rating", { average: this.get("average") });
|
return I18n.t("poll.average_rating", { average: this.get("average") });
|
||||||
}.property("average"),
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
import User from 'discourse/models/user';
|
||||||
|
import PollVoters from 'discourse/plugins/poll/components/poll-voters';
|
||||||
|
|
||||||
|
export default PollVoters.extend({
|
||||||
|
@computed("pollsVoters", "option.voter_ids", "showMore", "isExpanded", "numOfVotersToShow")
|
||||||
|
users(pollsVoters, voterIds, showMore, isExpanded, numOfVotersToShow) {
|
||||||
|
var users = [];
|
||||||
|
|
||||||
|
if (showMore && !isExpanded) {
|
||||||
|
voterIds = voterIds.slice(0, numOfVotersToShow);
|
||||||
|
}
|
||||||
|
|
||||||
|
voterIds.forEach(voterId => {
|
||||||
|
users.push(pollsVoters[voterId]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return users;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("option.votes", "numOfVotersToShow")
|
||||||
|
showMore(numOfVotes, numOfVotersToShow) {
|
||||||
|
return !(numOfVotes < numOfVotersToShow);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
export default Ember.Component.extend({
|
||||||
|
layoutName: "components/poll-voters",
|
||||||
|
tagName: 'ul',
|
||||||
|
classNames: ["poll-voters-list"],
|
||||||
|
isExpanded: false,
|
||||||
|
numOfVotersToShow: 20,
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
toggleExpand() {
|
||||||
|
this.toggleProperty("isExpanded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -6,6 +6,7 @@ export default Ember.Controller.extend({
|
||||||
isNumber: Ember.computed.equal("poll.type", "number"),
|
isNumber: Ember.computed.equal("poll.type", "number"),
|
||||||
isRandom : Ember.computed.equal("poll.order", "random"),
|
isRandom : Ember.computed.equal("poll.order", "random"),
|
||||||
isClosed: Ember.computed.equal("poll.status", "closed"),
|
isClosed: Ember.computed.equal("poll.status", "closed"),
|
||||||
|
pollsVoters: Ember.computed.alias("post.polls_voters"),
|
||||||
|
|
||||||
// shows the results when
|
// shows the results when
|
||||||
// - poll is closed
|
// - poll is closed
|
||||||
|
@ -145,8 +146,16 @@ export default Ember.Controller.extend({
|
||||||
options: this.get("selectedOptions"),
|
options: this.get("selectedOptions"),
|
||||||
}
|
}
|
||||||
}).then(results => {
|
}).then(results => {
|
||||||
this.setProperties({ vote: results.vote, showResults: true });
|
const poll = results.poll;
|
||||||
this.set("model", Em.Object.create(results.poll));
|
const votes = results.vote;
|
||||||
|
const currentUser = this.currentUser;
|
||||||
|
|
||||||
|
this.setProperties({ vote: votes, showResults: true });
|
||||||
|
this.set("model", Em.Object.create(poll));
|
||||||
|
|
||||||
|
if (poll.public) {
|
||||||
|
this.get("pollsVoters")[currentUser.get("id")] = currentUser;
|
||||||
|
}
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
bootbox.alert(I18n.t("poll.error_while_casting_votes"));
|
bootbox.alert(I18n.t("poll.error_while_casting_votes"));
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
{{{averageRating}}}
|
{{{averageRating}}}
|
||||||
|
|
||||||
|
{{#if poll.public}}
|
||||||
|
{{poll-results-number-voters poll=poll pollsVoters=pollsVoters}}
|
||||||
|
{{/if}}
|
||||||
|
|
|
@ -9,5 +9,9 @@
|
||||||
<div class="bar-back">
|
<div class="bar-back">
|
||||||
<div class="bar" style={{option.style}}></div>
|
<div class="bar" style={{option.style}}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if poll.public}}
|
||||||
|
{{poll-results-standard-voters option=option pollsVoters=pollsVoters}}
|
||||||
|
{{/if}}
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="poll-voters">
|
||||||
|
{{#each users as |user|}}
|
||||||
|
<li>
|
||||||
|
<a data-user-card={{unbound user.username}}>
|
||||||
|
{{avatar user imageSize="tiny"}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
<div class="poll-voters-toggle-expand">
|
||||||
|
{{#if showMore}}
|
||||||
|
{{#if isExpanded}}
|
||||||
|
<a {{action "toggleExpand"}}>{{fa-icon "chevron-up"}}</a>
|
||||||
|
{{else}}
|
||||||
|
<a {{action "toggleExpand"}}>{{fa-icon "chevron-down"}}</a>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -2,9 +2,9 @@
|
||||||
<div class="poll-container">
|
<div class="poll-container">
|
||||||
{{#if showingResults}}
|
{{#if showingResults}}
|
||||||
{{#if isNumber}}
|
{{#if isNumber}}
|
||||||
{{poll-results-number poll=poll}}
|
{{poll-results-number poll=poll pollsVoters=pollsVoters}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{poll-results-standard poll=poll}}
|
{{poll-results-standard poll=poll pollsVoters=pollsVoters}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
import { withPluginApi } from 'discourse/lib/plugin-api';
|
import { withPluginApi } from 'discourse/lib/plugin-api';
|
||||||
|
import { observes } from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
function createPollView(container, post, poll, vote) {
|
function createPollView(container, post, poll, vote, publicPoll) {
|
||||||
const controller = container.lookup("controller:poll", { singleton: false });
|
const controller = container.lookup("controller:poll", { singleton: false });
|
||||||
const view = container.lookup("view:poll");
|
const view = container.lookup("view:poll");
|
||||||
|
|
||||||
controller.set("vote", vote);
|
controller.setProperties({
|
||||||
controller.setProperties({ model: poll, post });
|
model: poll,
|
||||||
|
vote: vote,
|
||||||
|
public: publicPoll,
|
||||||
|
post
|
||||||
|
});
|
||||||
|
|
||||||
view.set("controller", controller);
|
view.set("controller", controller);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
@ -23,6 +29,10 @@ function initializePolls(api) {
|
||||||
const post = this.get('model.postStream').findLoadedPost(msg.post_id);
|
const post = this.get('model.postStream').findLoadedPost(msg.post_id);
|
||||||
if (post) {
|
if (post) {
|
||||||
post.set('polls', msg.polls);
|
post.set('polls', msg.polls);
|
||||||
|
|
||||||
|
if (msg.user) {
|
||||||
|
post.set(`polls_voters.${msg.user.id}`, msg.user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -38,7 +48,8 @@ function initializePolls(api) {
|
||||||
pollsObject: null,
|
pollsObject: null,
|
||||||
|
|
||||||
// we need a proper ember object so it is bindable
|
// we need a proper ember object so it is bindable
|
||||||
pollsChanged: function(){
|
@observes("polls")
|
||||||
|
pollsChanged() {
|
||||||
const polls = this.get("polls");
|
const polls = this.get("polls");
|
||||||
if (polls) {
|
if (polls) {
|
||||||
this._polls = this._polls || {};
|
this._polls = this._polls || {};
|
||||||
|
@ -52,7 +63,7 @@ function initializePolls(api) {
|
||||||
});
|
});
|
||||||
this.set("pollsObject", this._polls);
|
this.set("pollsObject", this._polls);
|
||||||
}
|
}
|
||||||
}.observes("polls")
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function cleanUpPollViews() {
|
function cleanUpPollViews() {
|
||||||
|
@ -69,6 +80,7 @@ function initializePolls(api) {
|
||||||
const post = helper.getModel();
|
const post = helper.getModel();
|
||||||
api.preventCloak(post.id);
|
api.preventCloak(post.id);
|
||||||
const votes = post.get('polls_votes') || {};
|
const votes = post.get('polls_votes') || {};
|
||||||
|
post.set("polls_voters", (post.get("polls_voters") || {}));
|
||||||
|
|
||||||
post.pollsChanged();
|
post.pollsChanged();
|
||||||
|
|
||||||
|
@ -82,8 +94,16 @@ function initializePolls(api) {
|
||||||
const $poll = $(pollElem);
|
const $poll = $(pollElem);
|
||||||
|
|
||||||
const pollName = $poll.data("poll-name");
|
const pollName = $poll.data("poll-name");
|
||||||
|
const publicPoll = $poll.data("poll-public");
|
||||||
const pollId = `${pollName}-${post.id}`;
|
const pollId = `${pollName}-${post.id}`;
|
||||||
const pollView = createPollView(helper.container, post, polls[pollName], votes[pollName]);
|
|
||||||
|
const pollView = createPollView(
|
||||||
|
helper.container,
|
||||||
|
post,
|
||||||
|
polls[pollName],
|
||||||
|
votes[pollName],
|
||||||
|
publicPoll
|
||||||
|
);
|
||||||
|
|
||||||
$poll.replaceWith($div);
|
$poll.replaceWith($div);
|
||||||
Em.run.next(() => pollView.renderer.replaceIn(pollView, $div[0]));
|
Em.run.next(() => pollView.renderer.replaceIn(pollView, $div[0]));
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
var DATA_PREFIX = "data-poll-";
|
var DATA_PREFIX = "data-poll-";
|
||||||
var DEFAULT_POLL_NAME = "poll";
|
var DEFAULT_POLL_NAME = "poll";
|
||||||
|
|
||||||
var WHITELISTED_ATTRIBUTES = ["type", "name", "min", "max", "step", "order", "status"];
|
var WHITELISTED_ATTRIBUTES = ["type", "name", "min", "max", "step", "order", "status", "public"];
|
||||||
|
|
||||||
var ATTRIBUTES_REGEX = new RegExp("(" + WHITELISTED_ATTRIBUTES.join("|") + ")=['\"]?[^\\s\\]]+['\"]?", "g");
|
var ATTRIBUTES_REGEX = new RegExp("(" + WHITELISTED_ATTRIBUTES.join("|") + ")=['\"]?[^\\s\\]]+['\"]?", "g");
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,12 @@ import { on } from "ember-addons/ember-computed-decorators";
|
||||||
export default Em.View.extend({
|
export default Em.View.extend({
|
||||||
templateName: "poll",
|
templateName: "poll",
|
||||||
classNames: ["poll"],
|
classNames: ["poll"],
|
||||||
attributeBindings: ["data-poll-type", "data-poll-name", "data-poll-status"],
|
attributeBindings: ["data-poll-type", "data-poll-name", "data-poll-status", "data-poll-public"],
|
||||||
|
|
||||||
poll: Em.computed.alias("controller.poll"),
|
poll: Em.computed.alias("controller.poll"),
|
||||||
|
|
||||||
"data-poll-type": Em.computed.alias("poll.type"),
|
"data-poll-type": Em.computed.alias("poll.type"),
|
||||||
"data-poll-name": Em.computed.alias("poll.name"),
|
"data-poll-name": Em.computed.alias("poll.name"),
|
||||||
"data-poll-status": Em.computed.alias("poll.status"),
|
"data-poll-status": Em.computed.alias("poll.status"),
|
||||||
|
"data-poll-public": Em.computed.alias("poll.public")
|
||||||
@on("didInsertElement")
|
|
||||||
_fixPollContainerHeight() {
|
|
||||||
const pollContainer = this.$(".poll-container");
|
|
||||||
pollContainer.height(pollContainer.height());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -92,6 +92,18 @@ div.poll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.poll-voters-list {
|
||||||
|
li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-voters-toggle-expand {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.results {
|
.results {
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
|
@ -120,9 +132,11 @@ div.poll {
|
||||||
|
|
||||||
&[data-poll-type="number"] {
|
&[data-poll-type="number"] {
|
||||||
|
|
||||||
li {
|
li[data-poll-option-id] {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 12px 15px 5px;
|
text-align: center;
|
||||||
|
width: 25px;
|
||||||
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module DiscoursePoll
|
module DiscoursePoll
|
||||||
class PollsUpdater
|
class PollsUpdater
|
||||||
VALID_POLLS_CONFIGS = %w{type min max}.map(&:freeze)
|
VALID_POLLS_CONFIGS = %w{type min max public}.map(&:freeze)
|
||||||
|
|
||||||
def self.update(post, polls)
|
def self.update(post, polls)
|
||||||
# load previous polls
|
# load previous polls
|
||||||
|
@ -53,11 +53,16 @@ module DiscoursePoll
|
||||||
polls[poll_name]["anonymous_voters"] = previous_polls[poll_name]["anonymous_voters"] if previous_polls[poll_name].has_key?("anonymous_voters")
|
polls[poll_name]["anonymous_voters"] = previous_polls[poll_name]["anonymous_voters"] if previous_polls[poll_name].has_key?("anonymous_voters")
|
||||||
|
|
||||||
previous_options = previous_polls[poll_name]["options"]
|
previous_options = previous_polls[poll_name]["options"]
|
||||||
|
public_poll = polls[poll_name]["public"] == "true"
|
||||||
|
|
||||||
polls[poll_name]["options"].each_with_index do |option, index|
|
polls[poll_name]["options"].each_with_index do |option, index|
|
||||||
previous_option = previous_options[index]
|
previous_option = previous_options[index]
|
||||||
option["votes"] = previous_option["votes"]
|
option["votes"] = previous_option["votes"]
|
||||||
option["anonymous_votes"] = previous_option["anonymous_votes"] if previous_option.has_key?("anonymous_votes")
|
option["anonymous_votes"] = previous_option["anonymous_votes"] if previous_option.has_key?("anonymous_votes")
|
||||||
|
|
||||||
|
if public_poll && previous_option.has_key?("voter_ids")
|
||||||
|
option["voter_ids"] = previous_option["voter_ids"]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ after_initialize do
|
||||||
|
|
||||||
raise StandardError.new I18n.t("poll.no_poll_with_this_name", name: poll_name) if poll.blank?
|
raise StandardError.new I18n.t("poll.no_poll_with_this_name", name: poll_name) if poll.blank?
|
||||||
raise StandardError.new I18n.t("poll.poll_must_be_open_to_vote") if poll["status"] != "open"
|
raise StandardError.new I18n.t("poll.poll_must_be_open_to_vote") if poll["status"] != "open"
|
||||||
|
public_poll = (poll["public"] == "true")
|
||||||
|
|
||||||
# remove options that aren't available in the poll
|
# remove options that aren't available in the poll
|
||||||
available_options = poll["options"].map { |o| o["id"] }.to_set
|
available_options = poll["options"].map { |o| o["id"] }.to_set
|
||||||
|
@ -80,12 +81,30 @@ after_initialize do
|
||||||
poll["options"].each do |option|
|
poll["options"].each do |option|
|
||||||
anonymous_votes = option["anonymous_votes"] || 0
|
anonymous_votes = option["anonymous_votes"] || 0
|
||||||
option["votes"] = all_options[option["id"]] + anonymous_votes
|
option["votes"] = all_options[option["id"]] + anonymous_votes
|
||||||
|
|
||||||
|
if public_poll
|
||||||
|
option["voter_ids"] ||= []
|
||||||
|
|
||||||
|
if options.include?(option["id"])
|
||||||
|
option["voter_ids"] << user_id if !option["voter_ids"].include?(user_id)
|
||||||
|
else
|
||||||
|
option["voter_ids"].delete(user_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
post.custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD] = polls
|
post.custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD] = polls
|
||||||
post.save_custom_fields(true)
|
post.save_custom_fields(true)
|
||||||
|
|
||||||
MessageBus.publish("/polls/#{post.topic_id}", { post_id: post_id, polls: polls })
|
payload = { post_id: post_id, polls: polls }
|
||||||
|
|
||||||
|
if public_poll
|
||||||
|
payload.merge!(
|
||||||
|
user: UserNameSerializer.new(User.find(user_id)).serializable_hash
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
MessageBus.publish("/polls/#{post.topic_id}", payload)
|
||||||
|
|
||||||
return [poll, options]
|
return [poll, options]
|
||||||
end
|
end
|
||||||
|
@ -195,7 +214,6 @@ after_initialize do
|
||||||
render_json_error e.message
|
render_json_error e.message
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
DiscoursePoll::Engine.routes.draw do
|
DiscoursePoll::Engine.routes.draw do
|
||||||
|
@ -271,11 +289,36 @@ after_initialize do
|
||||||
add_to_serializer(:post, :polls, false) { post_custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD] }
|
add_to_serializer(:post, :polls, false) { post_custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD] }
|
||||||
add_to_serializer(:post, :include_polls?) { post_custom_fields.present? && post_custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD].present? }
|
add_to_serializer(:post, :include_polls?) { post_custom_fields.present? && post_custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD].present? }
|
||||||
|
|
||||||
add_to_serializer(:post, :polls_votes, false) { post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD]["#{scope.user.id}"] }
|
add_to_serializer(:post, :polls_votes, false) do
|
||||||
|
post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD]["#{scope.user.id}"]
|
||||||
|
end
|
||||||
|
|
||||||
add_to_serializer(:post, :include_polls_votes?) do
|
add_to_serializer(:post, :include_polls_votes?) do
|
||||||
return unless scope.user
|
return unless scope.user
|
||||||
return unless post_custom_fields.present?
|
return unless post_custom_fields.present?
|
||||||
return unless post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].present?
|
return unless post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].present?
|
||||||
post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].has_key?("#{scope.user.id}")
|
post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].has_key?("#{scope.user.id}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_to_serializer(:post, :polls_voters) do
|
||||||
|
voters = {}
|
||||||
|
|
||||||
|
user_ids = post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].keys
|
||||||
|
|
||||||
|
User.where(id: user_ids).map do |user|
|
||||||
|
voters[user.id] = UserNameSerializer.new(user).serializable_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
voters
|
||||||
|
end
|
||||||
|
|
||||||
|
add_to_serializer(:post, :include_polls_voters?) do
|
||||||
|
return unless post_custom_fields.present?
|
||||||
|
return unless post_custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD].present?
|
||||||
|
return unless post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].present?
|
||||||
|
|
||||||
|
post_custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD].any? do |_, value|
|
||||||
|
value["public"] == "true"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -98,6 +98,49 @@ describe ::DiscoursePoll::PollsController do
|
||||||
expect(json["poll"]["options"][0]["votes"]).to eq(12)
|
expect(json["poll"]["options"][0]["votes"]).to eq(12)
|
||||||
expect(json["poll"]["options"][1]["votes"]).to eq(6)
|
expect(json["poll"]["options"][1]["votes"]).to eq(6)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "tracks the users ids for public polls" do
|
||||||
|
public_poll = Fabricate(:post, topic_id: topic.id, user_id: user.id, raw: "[poll public=true]\n- A\n- B\n[/poll]")
|
||||||
|
body = { post_id: public_poll.id, poll_name: "poll" }
|
||||||
|
|
||||||
|
message = MessageBus.track_publish do
|
||||||
|
xhr :put, :vote, body.merge(options: ["5c24fc1df56d764b550ceae1b9319125"])
|
||||||
|
end.first
|
||||||
|
|
||||||
|
expect(response).to be_success
|
||||||
|
|
||||||
|
json = ::JSON.parse(response.body)
|
||||||
|
expect(json["poll"]["voters"]).to eq(1)
|
||||||
|
expect(json["poll"]["options"][0]["votes"]).to eq(1)
|
||||||
|
expect(json["poll"]["options"][1]["votes"]).to eq(0)
|
||||||
|
expect(json["poll"]["options"][0]["voter_ids"]).to eq([user.id])
|
||||||
|
expect(json["poll"]["options"][1]["voter_ids"]).to eq([])
|
||||||
|
expect(message.data[:post_id].to_i).to eq(public_poll.id)
|
||||||
|
expect(message.data[:user][:id].to_i).to eq(user.id)
|
||||||
|
|
||||||
|
xhr :put, :vote, body.merge(options: ["e89dec30bbd9bf50fabf6a05b4324edf"])
|
||||||
|
expect(response).to be_success
|
||||||
|
|
||||||
|
json = ::JSON.parse(response.body)
|
||||||
|
expect(json["poll"]["voters"]).to eq(1)
|
||||||
|
expect(json["poll"]["options"][0]["votes"]).to eq(0)
|
||||||
|
expect(json["poll"]["options"][1]["votes"]).to eq(1)
|
||||||
|
expect(json["poll"]["options"][0]["voter_ids"]).to eq([])
|
||||||
|
expect(json["poll"]["options"][1]["voter_ids"]).to eq([user.id])
|
||||||
|
|
||||||
|
another_user = Fabricate(:user)
|
||||||
|
log_in_user(another_user)
|
||||||
|
|
||||||
|
xhr :put, :vote, body.merge(options: ["e89dec30bbd9bf50fabf6a05b4324edf", "5c24fc1df56d764b550ceae1b9319125"])
|
||||||
|
expect(response).to be_success
|
||||||
|
|
||||||
|
json = ::JSON.parse(response.body)
|
||||||
|
expect(json["poll"]["voters"]).to eq(2)
|
||||||
|
expect(json["poll"]["options"][0]["votes"]).to eq(1)
|
||||||
|
expect(json["poll"]["options"][1]["votes"]).to eq(2)
|
||||||
|
expect(json["poll"]["options"][0]["voter_ids"]).to eq([another_user.id])
|
||||||
|
expect(json["poll"]["options"][1]["voter_ids"]).to eq([user.id, another_user.id])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#toggle_status" do
|
describe "#toggle_status" do
|
||||||
|
|
|
@ -89,6 +89,69 @@ describe DiscoursePoll::PollsUpdater do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "public polls" do
|
||||||
|
let(:post) do
|
||||||
|
raw = <<-RAW.strip_heredoc
|
||||||
|
[poll public=true]
|
||||||
|
- A
|
||||||
|
- B
|
||||||
|
[/poll]
|
||||||
|
RAW
|
||||||
|
|
||||||
|
Fabricate(:post, raw: raw)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:private_poll) do
|
||||||
|
raw = <<-RAW.strip_heredoc
|
||||||
|
[poll]
|
||||||
|
- A
|
||||||
|
- B
|
||||||
|
[/poll]
|
||||||
|
RAW
|
||||||
|
|
||||||
|
DiscoursePoll::PollsValidator.new(Fabricate(:post, raw: raw)).validate_polls
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:public_poll) do
|
||||||
|
raw = <<-RAW.strip_heredoc
|
||||||
|
[poll public=true]
|
||||||
|
- A
|
||||||
|
- C
|
||||||
|
[/poll]
|
||||||
|
RAW
|
||||||
|
|
||||||
|
DiscoursePoll::PollsValidator.new(Fabricate(:post, raw: raw)).validate_polls
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
DiscoursePoll::Poll.vote(post.id, "poll", ["5c24fc1df56d764b550ceae1b9319125"], user.id)
|
||||||
|
post.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should retain voter_ids when options have been edited" do
|
||||||
|
described_class.update(post, public_poll)
|
||||||
|
|
||||||
|
polls = post.reload.custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD]
|
||||||
|
|
||||||
|
expect(polls["poll"]["options"][0]["voter_ids"]).to eq([user.id])
|
||||||
|
expect(polls["poll"]["options"][1]["voter_ids"]).to eq([])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should delete voter_ids when poll is set to private" do
|
||||||
|
described_class.update(post, private_poll)
|
||||||
|
|
||||||
|
polls = post.reload.custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD]
|
||||||
|
|
||||||
|
expect(post.reload.custom_fields[DiscoursePoll::POLLS_CUSTOM_FIELD])
|
||||||
|
.to eq(private_poll)
|
||||||
|
|
||||||
|
expect(polls["poll"]["options"][0]["voter_ids"]).to eq(nil)
|
||||||
|
expect(polls["poll"]["options"][1]["voter_ids"]).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "polls of type 'multiple'" do
|
context "polls of type 'multiple'" do
|
||||||
let(:min_2_post) do
|
let(:min_2_post) do
|
||||||
raw = <<-RAW.strip_heredoc
|
raw = <<-RAW.strip_heredoc
|
||||||
|
|
Loading…
Reference in a new issue