diff --git a/app/assets/javascripts/discourse/app/controllers/composer.js b/app/assets/javascripts/discourse/app/controllers/composer.js index c2fd4ba2385..488a975bd93 100644 --- a/app/assets/javascripts/discourse/app/controllers/composer.js +++ b/app/assets/javascripts/discourse/app/controllers/composer.js @@ -648,9 +648,19 @@ export default Controller.extend({ } const topic = composer.topic; + const slowModePost = + topic && topic.slow_mode_seconds && topic.user_last_posted_at; + const notEditing = this.get("model.action") !== "edit"; - if (topic && topic.slow_mode_seconds && topic.user_last_posted_at) { - if (cannotPostAgain(topic.slow_mode_seconds, topic.user_last_posted_at)) { + // Editing a topic in slow mode is directly handled by the backend. + if (slowModePost && notEditing) { + if ( + cannotPostAgain( + this.currentUser, + topic.slow_mode_seconds, + topic.user_last_posted_at + ) + ) { const message = I18n.t("composer.slow_mode.error"); bootbox.alert(message); diff --git a/app/assets/javascripts/discourse/app/helpers/slow-mode.js b/app/assets/javascripts/discourse/app/helpers/slow-mode.js index c8f138805ac..1191c68cd74 100644 --- a/app/assets/javascripts/discourse/app/helpers/slow-mode.js +++ b/app/assets/javascripts/discourse/app/helpers/slow-mode.js @@ -29,9 +29,9 @@ export function durationTextFromSeconds(seconds) { return moment.duration(seconds, "seconds").humanize(); } -export function cannotPostAgain(duration, last_posted_at) { +export function cannotPostAgain(user, duration, last_posted_at) { let threshold = new Date(last_posted_at); threshold = new Date(threshold.getTime() + duration * 1000); - return new Date() < threshold; + return !user.staff && new Date() < threshold; } diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index d20a4345fe4..d5bb5e39f16 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -383,6 +383,7 @@ en: too_late_to_edit: "That post was created too long ago. It can no longer be edited or deleted." edit_conflict: "That post was edited by another user and your changes can no longer be saved." revert_version_same: "The current version is same as the version you are trying to revert to." + cannot_edit_on_slow_mode: "The topic is in slow mode and that post can no longer be edited." excerpt_image: "image" diff --git a/lib/guardian/topic_guardian.rb b/lib/guardian/topic_guardian.rb index 71cb561518b..77e6ff9d22f 100644 --- a/lib/guardian/topic_guardian.rb +++ b/lib/guardian/topic_guardian.rb @@ -219,4 +219,8 @@ module TopicGuardian can_perform_action_available_to_group_moderators?(topic) end + def affected_by_slow_mode?(topic) + topic&.slow_mode_seconds.to_i > 0 && @user.human? && !is_staff? + end + end diff --git a/lib/post_creator.rb b/lib/post_creator.rb index 3fb1324195e..ad7f0e74b25 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -159,7 +159,7 @@ class PostCreator return false end - if @topic&.slow_mode_seconds.to_i > 0 + if guardian.affected_by_slow_mode?(@topic) tu = TopicUser.find_by(user: @user, topic: @topic) if tu&.last_posted_at diff --git a/lib/post_revisor.rb b/lib/post_revisor.rb index a9912d6dfb1..fc521f9e848 100644 --- a/lib/post_revisor.rb +++ b/lib/post_revisor.rb @@ -144,6 +144,11 @@ class PostRevisor @revised_at = @opts[:revised_at] || Time.now @last_version_at = @post.last_version_at || Time.now + if guardian.affected_by_slow_mode?(@topic) && !ninja_edit? + @post.errors.add(:base, I18n.t("cannot_edit_on_slow_mode")) + return false + end + @version_changed = false @post_successfully_saved = true @@ -194,7 +199,7 @@ class PostRevisor # We log staff/group moderator edits to posts if ( - (@editor.staff? || (@post.is_category_description? && Guardian.new(@editor).can_edit_category_description?(@post.topic.category))) && + (@editor.staff? || (@post.is_category_description? && guardian.can_edit_category_description?(@post.topic.category))) && @editor.id != @post.user_id && @fields.has_key?('raw') && !@opts[:skip_staff_log] @@ -639,4 +644,8 @@ class PostRevisor @post_successfully_saved && !@topic_changes.errored? end + def guardian + @guardian ||= Guardian.new(@editor) + end + end diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index 25115937717..c59d92c7273 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -747,6 +747,17 @@ describe PostCreator do expect(post).to be_present expect(creator.errors.count).to be_zero end + + it 'creates the topic if the user is a staff member' do + admin = Fabricate(:admin) + post_creator = PostCreator.new(admin, raw: 'test reply', topic_id: topic.id, reply_to_post_number: 4) + TopicUser.create!(user: admin, topic: topic, last_posted_at: 10.minutes.ago) + + post = post_creator.create + + expect(post).to be_present + expect(post_creator.errors.count).to be_zero + end end end diff --git a/spec/components/post_revisor_spec.rb b/spec/components/post_revisor_spec.rb index 89c3a78ad52..00f49f1342a 100644 --- a/spec/components/post_revisor_spec.rb +++ b/spec/components/post_revisor_spec.rb @@ -128,6 +128,38 @@ describe PostRevisor do end end + describe 'topic is in slow mode' do + before do + topic.update!(slow_mode_seconds: 1000) + end + + it 'regular edit' do + subject.revise!(post.user, { raw: 'updated body' }, revised_at: post.updated_at + 10.minutes) + + expect(post.errors.present?).to eq(true) + expect(post.errors.messages[:base].first).to be I18n.t("cannot_edit_on_slow_mode") + end + + it 'ninja editing is allowed' do + SiteSetting.editing_grace_period = 1.minute + + subject.revise!(post.user, { raw: 'updated body' }, revised_at: post.updated_at + 10.seconds) + + post.reload + + expect(post.errors).to be_empty + end + + it 'staff is allowed to edit posts even if the topic is in slow mode' do + admin = Fabricate(:admin) + subject.revise!(admin, { raw: 'updated body' }, revised_at: post.updated_at + 10.minutes) + + post.reload + + expect(post.errors).to be_empty + end + end + describe 'ninja editing' do it 'correctly applies edits' do SiteSetting.editing_grace_period = 1.minute