mirror of
https://github.com/discourse/discourse.git
synced 2024-12-04 14:44:06 +08:00
6a143030f8
They can use the remove vote button or select the same option again for single choice polls. This commit refactor the plugin to properly organize code and make it easier to follow.
447 lines
13 KiB
Ruby
447 lines
13 KiB
Ruby
# frozen_string_literal: true
|
||
|
||
require "rails_helper"
|
||
|
||
describe PostsController do
|
||
let!(:user) { log_in }
|
||
let!(:title) { "Testing Poll Plugin" }
|
||
|
||
before do
|
||
SiteSetting.min_first_post_typing_time = 0
|
||
end
|
||
|
||
describe "polls" do
|
||
it "works" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.exists?(post_id: json["id"])).to eq(true)
|
||
end
|
||
|
||
it "works on any post" do
|
||
post_1 = Fabricate(:post)
|
||
|
||
post :create, params: {
|
||
topic_id: post_1.topic.id, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.exists?(post_id: json["id"])).to eq(true)
|
||
end
|
||
|
||
it "schedules auto-close job" do
|
||
freeze_time
|
||
name = "auto_close"
|
||
close_date = 1.month.from_now.round
|
||
|
||
expect do
|
||
post :create, params: {
|
||
title: title,
|
||
raw: "[poll name=#{name} close=#{close_date.iso8601}]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
end.to change { Jobs::ClosePoll.jobs.size }.by(1) &
|
||
change { Poll.count }.by(1)
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
post_id = json["id"]
|
||
|
||
expect(Poll.find_by(post_id: post_id).close_at).to eq_time(close_date)
|
||
|
||
job = Jobs::ClosePoll.jobs.first
|
||
job_args = job["args"].first
|
||
|
||
expect(job_args["post_id"]).to eq(post_id)
|
||
expect(job_args["poll_name"]).to eq(name)
|
||
end
|
||
|
||
it "should have different options" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- A\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.default_poll_must_have_different_options"))
|
||
end
|
||
|
||
it "accepts different Chinese options" do
|
||
SiteSetting.default_locale = 'zh_CN'
|
||
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- Microsoft Edge(新)\n- Microsoft Edge(旧)\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).to be_successful
|
||
end
|
||
|
||
it "should have at least 1 options" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.default_poll_must_have_at_least_1_option"))
|
||
end
|
||
|
||
it "should have at most 'SiteSetting.poll_maximum_options' options" do
|
||
raw = +"[poll]\n"
|
||
(SiteSetting.poll_maximum_options + 1).times { |n| raw << "\n- #{n}" }
|
||
raw << "\n[/poll]"
|
||
|
||
post :create, params: {
|
||
title: title, raw: raw
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.default_poll_must_have_less_options", count: SiteSetting.poll_maximum_options))
|
||
end
|
||
|
||
it "should have valid parameters" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll type=multiple min=5]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.default_poll_with_multiple_choices_has_invalid_parameters"))
|
||
end
|
||
|
||
it "prevents self-xss" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll name=<script>alert('xss')</script>]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(json["cooked"]).to include("<script>")
|
||
expect(Poll.find_by(post_id: json["id"]).name).to eq("<script>alert('xss')</script>")
|
||
end
|
||
|
||
it "also works when there is a link starting with '[poll'" do
|
||
post :create, params: {
|
||
title: title, raw: "[Polls are awesome](/foobar)\n[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.exists?(post_id: json["id"])).to eq(true)
|
||
end
|
||
|
||
it "prevents poll-inception" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll name=1]\n- A\n[poll name=2]\n- B\n- C\n[/poll]\n- D\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.where(post_id: json["id"]).count).to eq(1)
|
||
end
|
||
|
||
it "accepts polls with titles" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n# What's up?\n- one\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).to be_successful
|
||
poll = Poll.last
|
||
expect(poll).to_not be_nil
|
||
expect(poll.title).to eq("What’s up?")
|
||
end
|
||
|
||
describe "edit window" do
|
||
|
||
describe "within the first 5 minutes" do
|
||
|
||
let(:post_id) do
|
||
freeze_time(4.minutes.ago) do
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
response.parsed_body["id"]
|
||
end
|
||
end
|
||
|
||
it "can be changed" do
|
||
put :update, params: {
|
||
id: post_id, post: { raw: "[poll]\n- A\n- B\n- C\n[/poll]" }
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["post"]["polls"][0]["options"][2]["html"]).to eq("C")
|
||
end
|
||
|
||
it "resets the votes" do
|
||
DiscoursePoll::Poll.vote(user, post_id, "poll", ["5c24fc1df56d764b550ceae1b9319125"])
|
||
|
||
put :update, params: {
|
||
id: post_id, post: { raw: "[poll]\n- A\n- B\n- C\n[/poll]" }
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["post"]["polls_votes"]).to_not be
|
||
end
|
||
|
||
end
|
||
|
||
describe "after the poll edit window has expired" do
|
||
|
||
let(:poll) { "[poll]\n- A\n- B\n[/poll]" }
|
||
let(:new_option) { "[poll]\n- A\n- C\n[/poll]" }
|
||
let(:updated) { "before\n\n[poll]\n- A\n- B\n[/poll]\n\nafter" }
|
||
|
||
let(:post_id) do
|
||
freeze_time(6.minutes.ago) do
|
||
post :create, params: {
|
||
title: title, raw: poll
|
||
}, format: :json
|
||
|
||
response.parsed_body["id"]
|
||
end
|
||
end
|
||
|
||
let(:poll_edit_window_mins) { 6 }
|
||
|
||
before do
|
||
SiteSetting.poll_edit_window_mins = poll_edit_window_mins
|
||
end
|
||
|
||
describe "with no vote" do
|
||
|
||
it "can change the options" do
|
||
put :update, params: {
|
||
id: post_id, post: { raw: new_option }
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["post"]["polls"][0]["options"][1]["html"]).to eq("C")
|
||
end
|
||
|
||
it "support changes on the post" do
|
||
put :update, params: { id: post_id, post: { raw: updated } }, format: :json
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["post"]["cooked"]).to match("before")
|
||
end
|
||
|
||
end
|
||
|
||
describe "with at least one vote" do
|
||
|
||
before do
|
||
DiscoursePoll::Poll.vote(user, post_id, "poll", ["5c24fc1df56d764b550ceae1b9319125"])
|
||
end
|
||
|
||
it "cannot change the options" do
|
||
put :update, params: {
|
||
id: post_id, post: { raw: new_option }
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t(
|
||
"poll.edit_window_expired.cannot_edit_default_poll_with_votes",
|
||
minutes: poll_edit_window_mins
|
||
))
|
||
end
|
||
|
||
it "support changes on the post" do
|
||
put :update, params: { id: post_id, post: { raw: updated } }, format: :json
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["post"]["cooked"]).to match("before")
|
||
end
|
||
|
||
end
|
||
|
||
end
|
||
|
||
end
|
||
|
||
end
|
||
|
||
describe "named polls" do
|
||
|
||
it "should have different options" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll name=""foo""]\n- A\n- A\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.named_poll_must_have_different_options", name: "foo"))
|
||
end
|
||
|
||
it "should have at least 1 option" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll name='foo']\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.named_poll_must_have_at_least_1_option", name: "foo"))
|
||
end
|
||
|
||
end
|
||
|
||
describe "multiple polls" do
|
||
|
||
it "works" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]\n[poll name=foo]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.where(post_id: json["id"]).count).to eq(2)
|
||
end
|
||
|
||
it "should have a name" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]\n[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.multiple_polls_without_name"))
|
||
end
|
||
|
||
it "should have unique name" do
|
||
post :create, params: {
|
||
title: title, raw: "[poll name=foo]\n- A\n- B\n[/poll]\n[poll name=foo]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.multiple_polls_with_same_name", name: "foo"))
|
||
end
|
||
|
||
end
|
||
|
||
describe "disabled polls" do
|
||
before do
|
||
SiteSetting.poll_enabled = false
|
||
end
|
||
|
||
it "doesn’t cook the poll" do
|
||
log_in_user(Fabricate(:user, admin: true, trust_level: 4))
|
||
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to eq("<p>[poll]</p>\n<ul>\n<li>A</li>\n<li>B<br>\n[/poll]</li>\n</ul>")
|
||
end
|
||
end
|
||
|
||
describe "regular user with insufficient trust level" do
|
||
before do
|
||
SiteSetting.poll_minimum_trust_level_to_create = 2
|
||
end
|
||
|
||
it "invalidates the post" do
|
||
log_in_user(Fabricate(:user, trust_level: 1))
|
||
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response).not_to be_successful
|
||
json = response.parsed_body
|
||
expect(json["errors"][0]).to eq(I18n.t("poll.insufficient_rights_to_create"))
|
||
end
|
||
|
||
it "skips the check in PMs with bots" do
|
||
user = Fabricate(:user, trust_level: 1)
|
||
topic = Fabricate(:private_message_topic, topic_allowed_users: [
|
||
Fabricate.build(:topic_allowed_user, user: user),
|
||
Fabricate.build(:topic_allowed_user, user: Discourse.system_user)
|
||
])
|
||
Fabricate(:post, topic_id: topic.id, user_id: Discourse::SYSTEM_USER_ID)
|
||
|
||
log_in_user(user)
|
||
|
||
post :create, params: {
|
||
topic_id: topic.id, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.parsed_body["errors"]).to eq(nil)
|
||
end
|
||
end
|
||
|
||
describe "regular user with equal trust level" do
|
||
before do
|
||
SiteSetting.poll_minimum_trust_level_to_create = 2
|
||
end
|
||
|
||
it "validates the post" do
|
||
log_in_user(Fabricate(:user, trust_level: 2))
|
||
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.exists?(post_id: json["id"])).to eq(true)
|
||
end
|
||
end
|
||
|
||
describe "regular user with superior trust level" do
|
||
before do
|
||
SiteSetting.poll_minimum_trust_level_to_create = 2
|
||
end
|
||
|
||
it "validates the post" do
|
||
log_in_user(Fabricate(:user, trust_level: 3))
|
||
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.exists?(post_id: json["id"])).to eq(true)
|
||
end
|
||
end
|
||
|
||
describe "staff with insufficient trust level" do
|
||
before do
|
||
SiteSetting.poll_minimum_trust_level_to_create = 2
|
||
end
|
||
|
||
it "validates the post" do
|
||
log_in_user(Fabricate(:user, moderator: true, trust_level: 1))
|
||
|
||
post :create, params: {
|
||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||
}, format: :json
|
||
|
||
expect(response.status).to eq(200)
|
||
json = response.parsed_body
|
||
expect(json["cooked"]).to match("data-poll-")
|
||
expect(Poll.exists?(post_id: json["id"])).to eq(true)
|
||
end
|
||
end
|
||
end
|