mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 08:53:38 +08:00
FEATURE: introduces minimum trust level for polls (#5391)
* FEATURE: introduces minimum trust level for polls This commit makes `poll_enabled` less misleading and introduces `poll_minimum_trust_level_to_create`. If poll are enabled they will always be cooked, and if you have the required trust level you can create polls. As a side effect, it also fixes a bug where rebaking a post created by staff member when `poll_enabled=false` would end up not cooking it. It also adds more tests to ensure settings are respected. * admins should be whitelisted * checks for admin in post validation * test for >= instead of == trust level
This commit is contained in:
parent
f466791a15
commit
63bab32816
|
@ -1,15 +1,22 @@
|
|||
import { withPluginApi } from 'discourse/lib/plugin-api';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import showModal from 'discourse/lib/show-modal';
|
||||
|
||||
function initializePollUIBuilder(api) {
|
||||
const siteSettings = api.container.lookup('site-settings:main');
|
||||
|
||||
if (!siteSettings.poll_enabled && (api.getCurrentUser() && !api.getCurrentUser().staff)) return;
|
||||
|
||||
api.modifyClass('controller:composer', {
|
||||
@computed('siteSettings.poll_enabled', 'siteSettings.poll_minimum_trust_level_to_create')
|
||||
canBuildPoll(pollEnabled, minimumTrustLevelToCreate) {
|
||||
return pollEnabled &&
|
||||
this.currentUser &&
|
||||
(
|
||||
this.currentUser.admin ||
|
||||
this.currentUser.trust_level >= minimumTrustLevelToCreate
|
||||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
showPollBuilder() {
|
||||
showModal("poll-ui-builder").set("toolbarEvent", this.get("toolbarEvent"));
|
||||
showModal('poll-ui-builder').set('toolbarEvent', this.get('toolbarEvent'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -18,13 +25,14 @@ function initializePollUIBuilder(api) {
|
|||
return {
|
||||
action: 'showPollBuilder',
|
||||
icon: 'bar-chart-o',
|
||||
label: 'poll.ui_builder.title'
|
||||
label: 'poll.ui_builder.title',
|
||||
condition: 'canBuildPoll'
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "add-poll-ui-builder",
|
||||
name: 'add-poll-ui-builder',
|
||||
|
||||
initialize() {
|
||||
withPluginApi('0.8.7', initializePollUIBuilder);
|
||||
|
|
|
@ -281,10 +281,7 @@ const rule = {
|
|||
|
||||
function newApiInit(helper) {
|
||||
helper.registerOptions((opts, siteSettings) => {
|
||||
const currentUser = (opts.getCurrentUser && opts.getCurrentUser(opts.userId)) || opts.currentUser;
|
||||
const staff = currentUser && currentUser.staff;
|
||||
|
||||
opts.features.poll = !!siteSettings.poll_enabled || staff;
|
||||
opts.features.poll = !!siteSettings.poll_enabled;
|
||||
opts.pollMaximumOptions = siteSettings.poll_maximum_options;
|
||||
});
|
||||
|
||||
|
|
|
@ -16,9 +16,10 @@
|
|||
|
||||
en:
|
||||
site_settings:
|
||||
poll_enabled: "Allow users to create polls?"
|
||||
poll_enabled: "Allow polls?"
|
||||
poll_maximum_options: "Maximum number of options allowed in a poll."
|
||||
poll_edit_window_mins: "Number of minutes after post creation during which polls can be edited."
|
||||
poll_minimum_trust_level_to_create: "Define the minimum trust level needed to create polls"
|
||||
|
||||
poll:
|
||||
multiple_polls_without_name: "There are multiple polls without a name. Use the '<code>name</code>' attribute to uniquely identify your polls."
|
||||
|
@ -61,5 +62,7 @@ en:
|
|||
topic_must_be_open_to_toggle_status: "The topic must be open to toggle status."
|
||||
only_staff_or_op_can_toggle_status: "Only a staff member or the original poster can toggle a poll status."
|
||||
|
||||
insufficient_trust_level_to_create: "Your trust level (%{current}) is insufficient to create polls (required: %{required})"
|
||||
|
||||
email:
|
||||
link_to_poll: "Click to view the poll."
|
||||
|
|
|
@ -7,3 +7,7 @@ plugins:
|
|||
client: true
|
||||
poll_edit_window_mins:
|
||||
default: 5
|
||||
poll_minimum_trust_level_to_create:
|
||||
default: 1
|
||||
client: true
|
||||
enum: 'TrustLevelSetting'
|
||||
|
|
25
plugins/poll/lib/post_validator.rb
Normal file
25
plugins/poll/lib/post_validator.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
module DiscoursePoll
|
||||
class PostValidator
|
||||
def initialize(post)
|
||||
@post = post
|
||||
end
|
||||
|
||||
def validate_post
|
||||
min_trust_level = SiteSetting.poll_minimum_trust_level_to_create
|
||||
trusted = @post&.user&.admin ||
|
||||
@post&.user&.trust_level >= TrustLevel[min_trust_level]
|
||||
|
||||
if !trusted
|
||||
message = I18n.t("poll.insufficient_trust_level_to_create",
|
||||
current: @post&.user&.trust_level,
|
||||
required: min_trust_level
|
||||
)
|
||||
|
||||
@post.errors.add(:base, message)
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,12 +14,12 @@ PLUGIN_NAME ||= "discourse_poll".freeze
|
|||
DATA_PREFIX ||= "data-poll-".freeze
|
||||
|
||||
after_initialize do
|
||||
|
||||
module ::DiscoursePoll
|
||||
DEFAULT_POLL_NAME ||= "poll".freeze
|
||||
POLLS_CUSTOM_FIELD ||= "polls".freeze
|
||||
VOTES_CUSTOM_FIELD ||= "polls-votes".freeze
|
||||
|
||||
autoload :PostValidator, "#{Rails.root}/plugins/poll/lib/post_validator"
|
||||
autoload :PollsValidator, "#{Rails.root}/plugins/poll/lib/polls_validator"
|
||||
autoload :PollsUpdater, "#{Rails.root}/plugins/poll/lib/polls_updater"
|
||||
|
||||
|
@ -314,6 +314,9 @@ after_initialize do
|
|||
# only care when raw has changed!
|
||||
return unless self.raw_changed? || force
|
||||
|
||||
validator = DiscoursePoll::PostValidator.new(self)
|
||||
return unless validator.validate_post
|
||||
|
||||
validator = DiscoursePoll::PollsValidator.new(self)
|
||||
return unless (polls = validator.validate_polls)
|
||||
|
||||
|
|
|
@ -336,4 +336,100 @@ describe PostsController do
|
|||
|
||||
end
|
||||
|
||||
describe "disabled polls" do
|
||||
before do
|
||||
SiteSetting.poll_enabled = false
|
||||
end
|
||||
|
||||
it "doesn’t cook the poll" do
|
||||
post :create, params: {
|
||||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||||
}, format: :json
|
||||
|
||||
expect(response).to be_success
|
||||
json = ::JSON.parse(response.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 "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_success
|
||||
json = ::JSON.parse(response.body)
|
||||
expect(json["errors"][0]).to eq(
|
||||
I18n.t("poll.insufficient_trust_level_to_create",
|
||||
current: user.trust_level,
|
||||
required: SiteSetting.poll_minimum_trust_level_to_create
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "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).to be_success
|
||||
json = ::JSON.parse(response.body)
|
||||
expect(json["cooked"]).to match("data-poll-")
|
||||
expect(json["polls"]["poll"]).to be
|
||||
end
|
||||
end
|
||||
|
||||
describe "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).to be_success
|
||||
json = ::JSON.parse(response.body)
|
||||
expect(json["cooked"]).to match("data-poll-")
|
||||
expect(json["polls"]["poll"]).to be
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "admin 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, admin: true, trust_level: 1))
|
||||
|
||||
post :create, params: {
|
||||
title: title, raw: "[poll]\n- A\n- B\n[/poll]"
|
||||
}, format: :json
|
||||
|
||||
expect(response).to be_success
|
||||
json = ::JSON.parse(response.body)
|
||||
expect(json["cooked"]).to match("data-poll-")
|
||||
expect(json["polls"]["poll"]).to be
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { displayPollBuilderButton } from "discourse/plugins/poll/helpers/display-poll-builder-button";
|
||||
import { replaceCurrentUser } from "discourse/plugins/poll/helpers/replace-current-user";
|
||||
|
||||
acceptance("Poll Builder - polls are disabled", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
poll_enabled: false,
|
||||
poll_minimum_trust_level_to_create: 2
|
||||
}
|
||||
});
|
||||
|
||||
test("sufficient trust level", (assert) => {
|
||||
replaceCurrentUser({ admin: false, trust_level: 3 });
|
||||
|
||||
displayPollBuilderButton();
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
|
||||
});
|
||||
});
|
||||
|
||||
test("insufficient trust level", (assert) => {
|
||||
replaceCurrentUser({ admin: false, trust_level: 1 });
|
||||
|
||||
displayPollBuilderButton();
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
|
||||
});
|
||||
});
|
||||
|
||||
test("admin", (assert) => {
|
||||
replaceCurrentUser({ admin: true });
|
||||
|
||||
displayPollBuilderButton();
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { displayPollBuilderButton } from "discourse/plugins/poll/helpers/display-poll-builder-button";
|
||||
import { replaceCurrentUser } from "discourse/plugins/poll/helpers/replace-current-user";
|
||||
|
||||
acceptance("Poll Builder - polls are enabled", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
poll_enabled: true,
|
||||
poll_minimum_trust_level_to_create: 1
|
||||
}
|
||||
});
|
||||
|
||||
test("sufficient trust level", (assert) => {
|
||||
replaceCurrentUser({ admin: false, trust_level: 1 });
|
||||
|
||||
displayPollBuilderButton();
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(exists("button[title='Build Poll']"), "it shows the builder button");
|
||||
});
|
||||
});
|
||||
|
||||
test("insufficient trust level", (assert) => {
|
||||
replaceCurrentUser({ admin: false, trust_level: 0 });
|
||||
|
||||
displayPollBuilderButton();
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(!exists("button[title='Build Poll']"), "it hides the builder button");
|
||||
});
|
||||
});
|
||||
|
||||
test("admin with insufficient trust level", (assert) => {
|
||||
replaceCurrentUser({ admin: true, trust_level: 0 });
|
||||
|
||||
displayPollBuilderButton();
|
||||
|
||||
andThen(() => {
|
||||
assert.ok(exists("button[title='Build Poll']"), "it shows the builder button");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
export function displayPollBuilderButton() {
|
||||
visit("/");
|
||||
click("#create-topic");
|
||||
click(".d-editor-button-bar .options");
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export function replaceCurrentUser(properties) {
|
||||
const currentUser = Discourse.User.current();
|
||||
currentUser.setProperties(properties);
|
||||
Discourse.User.resetCurrent(currentUser);
|
||||
}
|
Loading…
Reference in New Issue
Block a user