FEATURE: Allow admins to reply without topic bump

This commit is contained in:
Gerhard Schlager 2018-08-10 02:48:30 +02:00 committed by Sam
parent 6ec92d5845
commit ef4b9f98c1
10 changed files with 182 additions and 10 deletions

View File

@ -53,7 +53,8 @@ function loadDraft(store, opts) {
composerTime: draft.composerTime,
typingTime: draft.typingTime,
whisper: draft.whisper,
tags: draft.tags
tags: draft.tags,
noBump: draft.noBump
});
return composer;
}
@ -194,6 +195,13 @@ export default Ember.Controller.extend({
}
},
@computed("model.noBump")
topicBumpText(noBump) {
if (noBump) {
return I18n.t("composer.no_topic_bump");
}
},
@computed
isStaffUser() {
const currentUser = this.currentUser;

View File

@ -41,7 +41,8 @@ const CLOSED = "closed",
composer_open_duration_msecs: "composerTime",
tags: "tags",
featured_link: "featuredLink",
shared_draft: "sharedDraft"
shared_draft: "sharedDraft",
no_bump: "noBump"
},
_edit_topic_serializer = {
title: "topic.title",
@ -71,6 +72,7 @@ const SAVE_ICONS = {
const Composer = RestModel.extend({
_categoryId: null,
unlistTopic: false,
noBump: false,
archetypes: function() {
return this.site.get("archetypes");
@ -608,7 +610,8 @@ const Composer = RestModel.extend({
composerTotalOpened: opts.composerTime,
typingTime: opts.typingTime,
whisper: opts.whisper,
tags: opts.tags
tags: opts.tags,
noBump: opts.noBump
});
if (opts.post) {
@ -714,7 +717,8 @@ const Composer = RestModel.extend({
typingTime: 0,
composerOpened: null,
composerTotalOpened: 0,
featuredLink: null
featuredLink: null,
noBump: false
});
},
@ -964,7 +968,8 @@ const Composer = RestModel.extend({
usernames: this.get("targetUsernames"),
composerTime: this.get("composerTime"),
typingTime: this.get("typingTime"),
tags: this.get("tags")
tags: this.get("tags"),
noBump: this.get("noBump")
};
this.set("draftStatus", I18n.t("composer.saving_draft_tip"));

View File

@ -21,6 +21,9 @@
{{#if whisperOrUnlistTopicText}}
<span class='whisper'>({{whisperOrUnlistTopicText}})</span>
{{/if}}
{{#if topicBumpText}}
<span class="no-bump">{{topicBumpText}}</span>
{{/if}}
{{/unless}}
{{#if canEdit}}
@ -120,6 +123,11 @@
{{d-icon "eye-slash"}}
</span>
{{/if}}
{{#if topicBumpText}}
<span class="no-bump">
{{d-icon "anchor"}}
</span>
{{/if}}
{{/if}}

View File

@ -192,6 +192,17 @@ export default DropdownSelectBoxComponent.extend({
});
}
const currentUser = Discourse.User.current();
if (action === REPLY && currentUser && currentUser.get("staff")) {
items.push({
name: I18n.t("composer.composer_actions.toggle_topic_bump.label"),
description: I18n.t("composer.composer_actions.toggle_topic_bump.desc"),
icon: "anchor",
id: "toggle_topic_bump"
});
}
return items;
},
@ -234,6 +245,10 @@ export default DropdownSelectBoxComponent.extend({
model.toggleProperty("whisper");
},
toggleTopicBumpSelected(options, model) {
model.toggleProperty("noBump");
},
replyToTopicSelected(options) {
options.action = REPLY;
options.topic = _topicSnapshot;

View File

@ -153,6 +153,7 @@
}
.whisper,
.no-bump,
.display-edit-reason {
font-style: italic;
}

View File

@ -653,6 +653,11 @@ class PostsController < ApplicationController
result[:is_warning] = false
end
if params[:no_bump] == "true"
raise Discourse::InvalidParameters.new(:no_bump) unless guardian.can_skip_bump?
result[:no_bump] = true
end
if params[:shared_draft] == 'true'
raise Discourse::InvalidParameters.new(:shared_draft) unless guardian.can_create_shared_draft?

View File

@ -1318,6 +1318,7 @@ en:
whisper: "whisper"
unlist: "unlisted"
blockquote_text: "Blockquote"
no_topic_bump: "(no bump)"
add_warning: "This is an official warning."
toggle_whisper: "Toggle Whisper"
@ -1437,6 +1438,9 @@ en:
shared_draft:
label: "Shared Draft"
desc: "Draft a topic that will only be visible to staff"
toggle_topic_bump:
label: "Toggle topic bump"
desc: "Reply without changing the topic's bump date"
notifications:
tooltip:

View File

@ -255,4 +255,8 @@ module PostGuardian
def can_unhide?(post)
post.try(:hidden) && is_staff?
end
def can_skip_bump?
is_staff?
end
end

View File

@ -1055,6 +1055,67 @@ describe PostsController do
end
end
end
context "topic bump" do
shared_examples "it works" do
let(:original_bumped_at) { 1.day.ago }
let!(:topic) { Fabricate(:topic, bumped_at: original_bumped_at) }
it "should be able to skip topic bumping" do
post "/posts.json", params: {
raw: 'this is the test content',
topic_id: topic.id,
no_bump: true
}
expect(response.status).to eq(200)
expect(topic.reload.bumped_at).to be_within_one_second_of(original_bumped_at)
end
it "should be able to post with topic bumping" do
post "/posts.json", params: {
raw: 'this is the test content',
topic_id: topic.id
}
expect(response.status).to eq(200)
expect(topic.reload.bumped_at).to eq(topic.posts.last.created_at)
end
end
context "admins" do
before do
sign_in(Fabricate(:admin))
end
include_examples "it works"
end
context "moderators" do
before do
sign_in(Fabricate(:moderator))
end
include_examples "it works"
end
context "users" do
let(:topic) { Fabricate(:topic) }
[:user, :trust_level_4].each do |user|
it "will raise an error for #{user}" do
sign_in(Fabricate(user))
post "/posts.json", params: {
raw: 'this is the test content',
topic_id: topic.id,
no_bump: true
}
expect(response.status).to eq(400)
end
end
end
end
end
describe '#revisions' do
@ -1524,5 +1585,4 @@ describe PostsController do
expect(public_post).not_to be_locked
end
end
end

View File

@ -1,4 +1,4 @@
import { acceptance } from "helpers/qunit-helpers";
import { acceptance, replaceCurrentUser } from "helpers/qunit-helpers";
import { _clearSnapshots } from "select-kit/components/composer-actions";
acceptance("Composer Actions", {
@ -25,7 +25,8 @@ QUnit.test("replying to post", async assert => {
);
assert.equal(composerActions.rowByIndex(2).value(), "reply_to_topic");
assert.equal(composerActions.rowByIndex(3).value(), "toggle_whisper");
assert.equal(composerActions.rowByIndex(4).value(), undefined);
assert.equal(composerActions.rowByIndex(4).value(), "toggle_topic_bump");
assert.equal(composerActions.rowByIndex(5).value(), undefined);
});
QUnit.test("replying to post - reply_as_private_message", async assert => {
@ -179,7 +180,8 @@ QUnit.test("interactions", async assert => {
"reply_as_private_message"
);
assert.equal(composerActions.rowByIndex(3).value(), "toggle_whisper");
assert.equal(composerActions.rows().length, 4);
assert.equal(composerActions.rowByIndex(4).value(), "toggle_topic_bump");
assert.equal(composerActions.rows().length, 5);
await composerActions.selectRowByValue("reply_to_post");
await composerActions.expand();
@ -199,7 +201,8 @@ QUnit.test("interactions", async assert => {
);
assert.equal(composerActions.rowByIndex(2).value(), "reply_to_topic");
assert.equal(composerActions.rowByIndex(3).value(), "toggle_whisper");
assert.equal(composerActions.rows().length, 4);
assert.equal(composerActions.rowByIndex(4).value(), "toggle_topic_bump");
assert.equal(composerActions.rows().length, 5);
await composerActions.selectRowByValue("reply_as_new_topic");
await composerActions.expand();
@ -243,3 +246,62 @@ QUnit.test("interactions", async assert => {
assert.equal(composerActions.rowByIndex(2).value(), "reply_to_topic");
assert.equal(composerActions.rows().length, 3);
});
QUnit.test("replying to post - toggle_topic_bump", async assert => {
const composerActions = selectKit(".composer-actions");
await visit("/t/internationalization-localization/280");
await click("article#post_3 button.reply");
assert.ok(
find(".composer-fields .no-bump").length === 0,
"no-bump text is not visible"
);
await composerActions.expand();
await composerActions.selectRowByValue("toggle_topic_bump");
assert.equal(
find(".composer-fields .no-bump").text(),
I18n.t("composer.no_topic_bump"),
"no-bump text is visible"
);
await composerActions.expand();
await composerActions.selectRowByValue("toggle_topic_bump");
assert.ok(
find(".composer-fields .no-bump").length === 0,
"no-bump text is not visible"
);
});
QUnit.test("replying to post as staff", async assert => {
const composerActions = selectKit(".composer-actions");
replaceCurrentUser({ staff: true, admin: false });
await visit("/t/internationalization-localization/280");
await click("article#post_3 button.reply");
await composerActions.expand();
assert.equal(composerActions.rows().length, 5);
assert.equal(composerActions.rowByIndex(4).value(), "toggle_topic_bump");
});
QUnit.test("replying to post as regular user", async assert => {
const composerActions = selectKit(".composer-actions");
replaceCurrentUser({ staff: false, admin: false });
await visit("/t/internationalization-localization/280");
await click("article#post_3 button.reply");
await composerActions.expand();
assert.equal(composerActions.rows().length, 3);
Array.from(composerActions.rows()).forEach(row => {
assert.notEqual(
row.value,
"toggle_topic_bump",
"toggle button is not visible"
);
});
});