FIX: poll when config is on_close only show results when poll is closed (#28299)

See: https://meta.discourse.org/t/cant-edit-topic-with-poll-bug-occurs/320845?u=merefield

When the Poll is set to "results ON_CLOSE", vote numbers for each option are only streamed to the browser when the vote is Closed. It is therefore not possible to render the Results.

The current issue is that when you refresh the page, for those that have voted the default view is results. For this type of poll this should NOT happen. The Results view in this mode should not be possible to see until closure, even for the Author.

Because the votes are not yet serialised when this kind of poll remains open, an attempt to display results causes a JavaScript exception and in any case does not make logical sense.

So the fix here is making sure the default view, for Polls that have results on close, is the voting view until the Poll is Closed.

I've added a test to cover this scenario.

Additionally, this requires a refresh of the page when the poll admin actions a Close to ensure the results are serialized in.
This commit is contained in:
Robert 2024-08-13 08:29:16 +01:00 committed by GitHub
parent 60d62f1b7e
commit 47f749744f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 62 additions and 6 deletions

View File

@ -26,7 +26,12 @@ export default class PollOptionsComponent extends Component {
this.args.sendOptionSelect(option, rank);
}
<template>
<ul class={{concatClass (if @isRankedChoice "ranked-choice-poll-options")}}>
<ul
class={{concatClass
(if @isRankedChoice "ranked-choice-poll-options")
"options"
}}
>
{{#each @options key="rank" as |option|}}
{{#if @isRankedChoice}}
<PollOptionRankedChoice

View File

@ -7,6 +7,9 @@ import PollVoters from "./poll-voters";
export default class PollResultsStandardComponent extends Component {
orderOptions = (options) => {
options.forEach((option) => {
option.votes = option.votes ?? 0;
});
return options.sort((a, b) => {
if (a.votes < b.votes) {
return 1;
@ -41,11 +44,11 @@ export default class PollResultsStandardComponent extends Component {
option.percentage = per;
option.chosen = chosen;
let voters = this.args.isPublic
? this.args.voters[option.id]?.voters || []
? this.args.voters?.[option.id]?.voters ?? []
: [];
option.voters = [...voters];
option.loading = this.args.isPublic
? this.args.voters[option.id]?.loading || false
? this.args.voters?.[option.id]?.loading ?? false
: false;
});

View File

@ -37,6 +37,7 @@ const OPEN_STATUS = "open";
export default class PollComponent extends Component {
@service currentUser;
@service siteSettings;
@service router;
@service appEvents;
@service dialog;
@service modal;
@ -48,9 +49,10 @@ export default class PollComponent extends Component {
@tracked
showResults =
this.hasSavedVote ||
(this.topicArchived && !this.staffOnly) ||
(this.closed && !this.staffOnly);
!(this.poll.results === ON_CLOSE && !this.closed) &&
(this.hasSavedVote ||
(this.topicArchived && !this.staffOnly) ||
(this.closed && !this.staffOnly));
@tracked showTally = false;
@ -595,6 +597,15 @@ export default class PollComponent extends Component {
) {
this.showResults = this.status === CLOSED_STATUS;
}
// Votes are only included in serialized results for results=ON_CLOSE when
// the poll is closed, so we must refresh the page to pick these up.
if (
this.poll.results === ON_CLOSE &&
this.status === CLOSED_STATUS
) {
this.router.refresh();
}
})
.catch((error) => {
if (error) {

View File

@ -86,6 +86,43 @@ module("Poll | Component | poll", function (hooks) {
);
});
test("does not show results after voting when results are to be shown only on closed", async function (assert) {
this.setProperties({
attributes: EmberObject.create({
post: EmberObject.create({
id: 42,
topic: {
archived: false,
},
user_id: 29,
}),
hasSavedVote: true,
poll: EmberObject.create({
name: "poll",
type: "regular",
status: "open",
results: "on_close",
options: [
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes" },
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no" },
],
voters: 1,
chart_type: "bar",
}),
vote: ["1f972d1df351de3ce35a787c89faad29"],
groupableUserFields: [],
}),
preloadedVoters: [],
});
await render(
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
);
assert.ok(exists("ul.options"), "options are shown");
assert.ok(!exists("ul.results"), "results are not shown");
});
test("can vote", async function (assert) {
this.setProperties({
attributes: EmberObject.create({