Merge pull request #4257 from tgxworld/paginate_public_polls
PERF: Paginate public polls.
This commit is contained in:
commit
494f1f9fae
|
@ -3,29 +3,14 @@ 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("poll.voters", "pollsVoters")
|
||||
canLoadMore(voters, pollsVoters) {
|
||||
return pollsVoters.length < voters;
|
||||
},
|
||||
|
||||
@computed("pollsVoters", "numOfVotersToShow")
|
||||
showMore(pollsVoters, numOfVotersToShow) {
|
||||
return !(Object.keys(pollsVoters).length < numOfVotersToShow);
|
||||
@computed("poll.options", "offset")
|
||||
voterIds(options) {
|
||||
const ids = [].concat(...(options.map(option => option.voter_ids)));
|
||||
return this._getIds(ids);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,8 +2,6 @@ import round from "discourse/lib/round";
|
|||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Em.Component.extend({
|
||||
tagName: "span",
|
||||
|
||||
@computed("poll.options.@each.{html,votes}")
|
||||
totalScore() {
|
||||
return _.reduce(this.get("poll.options"), function(total, o) {
|
||||
|
|
|
@ -3,23 +3,13 @@ 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", "pollsVoters")
|
||||
canLoadMore(voters, pollsVoters) {
|
||||
return pollsVoters.length < voters;
|
||||
},
|
||||
|
||||
@computed("option.votes", "numOfVotersToShow")
|
||||
showMore(numOfVotes, numOfVotersToShow) {
|
||||
return !(numOfVotes < numOfVotersToShow);
|
||||
@computed("option.voter_ids", "offset")
|
||||
voterIds(ids) {
|
||||
return this._getIds(ids);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,11 +3,51 @@ export default Ember.Component.extend({
|
|||
tagName: 'ul',
|
||||
classNames: ["poll-voters-list"],
|
||||
isExpanded: false,
|
||||
numOfVotersToShow: 20,
|
||||
numOfVotersToShow: 0,
|
||||
offset: 0,
|
||||
loading: false,
|
||||
pollsVoters: null,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
this.set("pollsVoters", []);
|
||||
},
|
||||
|
||||
_fetchUsers() {
|
||||
this.set("loading", true);
|
||||
|
||||
Discourse.ajax("/polls/voters.json", {
|
||||
type: "get",
|
||||
data: { user_ids: this.get("voterIds") }
|
||||
}).then(result => {
|
||||
if (this.isDestroyed) return;
|
||||
this.set("pollsVoters", this.get("pollsVoters").concat(result.users));
|
||||
this.incrementProperty("offset");
|
||||
this.set("loading", false);
|
||||
}).catch((error) => {
|
||||
Ember.logger.log(error);
|
||||
bootbox.alert(I18n.t('poll.error_while_fetching_voters'));
|
||||
});
|
||||
},
|
||||
|
||||
_getIds(ids) {
|
||||
const numOfVotersToShow = this.get("numOfVotersToShow");
|
||||
const offset = this.get("offset");
|
||||
return ids.slice(numOfVotersToShow * offset, numOfVotersToShow * (offset + 1));
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this.set("numOfVotersToShow", Math.round(this.$().width() / 25) * 2);
|
||||
if (this.get("voterIds").length > 0) this._fetchUsers();
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleExpand() {
|
||||
this.toggleProperty("isExpanded");
|
||||
loadMore() {
|
||||
this._fetchUsers();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@ export default Ember.Controller.extend({
|
|||
isRandom : Ember.computed.equal("poll.order", "random"),
|
||||
isClosed: Ember.computed.equal("poll.status", "closed"),
|
||||
isPublic: Ember.computed.equal("poll.public", "true"),
|
||||
pollsVoters: Ember.computed.alias("post.polls_voters"),
|
||||
|
||||
// shows the results when
|
||||
// - poll is closed
|
||||
|
@ -152,10 +151,6 @@ export default Ember.Controller.extend({
|
|||
|
||||
this.setProperties({ vote: votes, showResults: true });
|
||||
this.set("model", Em.Object.create(poll));
|
||||
|
||||
if (poll.public) {
|
||||
this.get("pollsVoters")[currentUser.get("id")] = currentUser;
|
||||
}
|
||||
}).catch(() => {
|
||||
bootbox.alert(I18n.t("poll.error_while_casting_votes"));
|
||||
}).finally(() => {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{{{averageRating}}}
|
||||
<div class="poll-results-number-rating">
|
||||
{{{averageRating}}}
|
||||
</div>
|
||||
|
||||
{{#if poll.public}}
|
||||
{{poll-results-number-voters poll=poll pollsVoters=pollsVoters}}
|
||||
{{poll-results-number-voters poll=poll}}
|
||||
{{/if}}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</div>
|
||||
|
||||
{{#if poll.public}}
|
||||
{{poll-results-standard-voters option=option pollsVoters=pollsVoters}}
|
||||
{{poll-results-standard-voters option=option}}
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="poll-voters">
|
||||
{{#each users as |user|}}
|
||||
{{#each pollsVoters as |user|}}
|
||||
<li>
|
||||
<a data-user-card={{unbound user.username}}>
|
||||
{{avatar user imageSize="tiny" ignoreTitle="true"}}
|
||||
|
@ -8,12 +8,10 @@
|
|||
{{/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 canLoadMore}}
|
||||
{{#conditional-loading-spinner condition=loading size="small"}}
|
||||
<a {{action "loadMore"}}>{{fa-icon "chevron-down"}}</a>
|
||||
{{/conditional-loading-spinner}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<div class="poll-container">
|
||||
{{#if showingResults}}
|
||||
{{#if isNumber}}
|
||||
{{poll-results-number poll=poll pollsVoters=pollsVoters}}
|
||||
{{poll-results-number poll=poll}}
|
||||
{{else}}
|
||||
{{poll-results-standard poll=poll pollsVoters=pollsVoters}}
|
||||
{{poll-results-standard poll=poll}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<ul>
|
||||
|
|
|
@ -29,10 +29,6 @@ function initializePolls(api) {
|
|||
const post = this.get('model.postStream').findLoadedPost(msg.post_id);
|
||||
if (post) {
|
||||
post.set('polls', msg.polls);
|
||||
|
||||
if (msg.user) {
|
||||
post.set(`polls_voters.${msg.user.id}`, msg.user);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -80,7 +76,6 @@ function initializePolls(api) {
|
|||
const post = helper.getModel();
|
||||
api.preventCloak(post.id);
|
||||
const votes = post.get('polls_votes') || {};
|
||||
post.set("polls_voters", (post.get("polls_voters") || {}));
|
||||
|
||||
post.pollsChanged();
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ div.poll {
|
|||
vertical-align: middle;
|
||||
padding: 10px;
|
||||
|
||||
& > span {
|
||||
.poll-results-number-rating {
|
||||
font-size: 2em;
|
||||
}
|
||||
}
|
||||
|
@ -97,10 +97,11 @@ div.poll {
|
|||
display: inline;
|
||||
}
|
||||
|
||||
margin: 5px 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.poll-voters-toggle-expand {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,3 +67,4 @@ en:
|
|||
|
||||
error_while_toggling_status: "There was an error while toggling the status of this poll."
|
||||
error_while_casting_votes: "There was an error while casting your votes."
|
||||
error_while_fetching_voters: "There was an error while displaying the voters."
|
||||
|
|
|
@ -185,7 +185,7 @@ after_initialize do
|
|||
class DiscoursePoll::PollsController < ::ApplicationController
|
||||
requires_plugin PLUGIN_NAME
|
||||
|
||||
before_filter :ensure_logged_in
|
||||
before_filter :ensure_logged_in, except: [:voters]
|
||||
|
||||
def vote
|
||||
post_id = params.require(:post_id)
|
||||
|
@ -214,11 +214,22 @@ after_initialize do
|
|||
render_json_error e.message
|
||||
end
|
||||
end
|
||||
|
||||
def voters
|
||||
user_ids = params.require(:user_ids)
|
||||
|
||||
users = User.where(id: user_ids).map do |user|
|
||||
UserNameSerializer.new(user).serializable_hash
|
||||
end
|
||||
|
||||
render json: { users: users }
|
||||
end
|
||||
end
|
||||
|
||||
DiscoursePoll::Engine.routes.draw do
|
||||
put "/vote" => "polls#vote"
|
||||
put "/toggle_status" => "polls#toggle_status"
|
||||
get "/voters" => 'polls#voters'
|
||||
end
|
||||
|
||||
Discourse::Application.routes.append do
|
||||
|
@ -299,26 +310,4 @@ after_initialize do
|
|||
return unless post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].present?
|
||||
post_custom_fields[DiscoursePoll::VOTES_CUSTOM_FIELD].has_key?("#{scope.user.id}")
|
||||
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
|
||||
|
|
|
@ -173,5 +173,4 @@ describe ::DiscoursePoll::PollsController do
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
require "rails_helper"
|
||||
|
||||
describe "DiscoursePoll endpoints" do
|
||||
describe "fetch voters from user_ids" do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
it "should return the right response" do
|
||||
get "/polls/voters.json", { user_ids: [user.id] }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
json = JSON.parse(response.body)["users"].first
|
||||
|
||||
expect(json["name"]).to eq(user.name)
|
||||
expect(json["title"]).to eq(user.title)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue