diff --git a/app/assets/javascripts/discourse/app/components/reviewable-item.js b/app/assets/javascripts/discourse/app/components/reviewable-item.js index d7647cbb5db..2c8705216b1 100644 --- a/app/assets/javascripts/discourse/app/components/reviewable-item.js +++ b/app/assets/javascripts/discourse/app/components/reviewable-item.js @@ -10,6 +10,8 @@ import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import optionalService from "discourse/lib/optional-service"; import Category from "discourse/models/category"; +import Composer from "discourse/models/composer"; +import Topic from "discourse/models/topic"; import discourseComputed, { bind } from "discourse-common/utils/decorators"; import I18n from "discourse-i18n"; @@ -45,6 +47,7 @@ export default Component.extend({ modal: service(), siteSettings: service(), currentUser: service(), + composer: service(), tagName: "", updating: null, editing: false, @@ -225,6 +228,34 @@ export default Component.extend({ this._penalize("showSilenceModal", reviewable, performAction); }, + async clientEdit(reviewable, performAction) { + if (!this.currentUser) { + return this.dialog.alert(I18n.t("post.controls.edit_anonymous")); + } + const post = await this.store.find("post", reviewable.post_id); + const topic_json = await Topic.find(post.topic_id, {}); + + const topic = Topic.create(topic_json); + post.set("topic", topic); + + if (!post.can_edit) { + return false; + } + + const opts = { + post, + action: Composer.EDIT, + draftKey: post.get("topic.draft_key"), + draftSequence: post.get("topic.draft_sequence"), + skipDraftCheck: true, + skipJumpOnSave: true, + }; + + this.composer.open(opts); + + return performAction(); + }, + _penalize(adminToolMethod, reviewable, performAction) { let adminTools = this.adminTools; if (adminTools) { diff --git a/app/models/reviewable_flagged_post.rb b/app/models/reviewable_flagged_post.rb index 69b29a4234e..d35736bc05a 100644 --- a/app/models/reviewable_flagged_post.rb +++ b/app/models/reviewable_flagged_post.rb @@ -9,6 +9,7 @@ class ReviewableFlaggedPost < Reviewable agree_and_keep_hidden: :agree_and_keep, agree_and_silence: :agree_and_keep, agree_and_suspend: :agree_and_keep, + agree_and_edit: :agree_and_keep, disagree_and_restore: :disagree, ignore_and_do_nothing: :ignore, } @@ -59,6 +60,13 @@ class ReviewableFlaggedPost < Reviewable build_action(actions, :agree_and_keep_hidden, icon: "thumbs-up", bundle: agree_bundle) else build_action(actions, :agree_and_keep, icon: "thumbs-up", bundle: agree_bundle) + build_action( + actions, + :agree_and_edit, + icon: "pencil-alt", + bundle: agree_bundle, + client_action: "edit", + ) end if guardian.can_delete_post_or_topic?(post) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index ecc3a6f7500..103a023d5c7 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -5524,6 +5524,9 @@ en: agree_and_hide: title: "Hide post" description: "Agree with flag and hide this post + automatically send the user a message urging them to edit it." + agree_and_edit: + title: "Agree and Edit Post" + description: "Agree with flag and open a composer window to edit the post." delete_single: title: "Delete" delete: diff --git a/spec/models/reviewable_flagged_post_spec.rb b/spec/models/reviewable_flagged_post_spec.rb index 5e8760df898..c556a3b1ed6 100644 --- a/spec/models/reviewable_flagged_post_spec.rb +++ b/spec/models/reviewable_flagged_post_spec.rb @@ -27,6 +27,7 @@ RSpec.describe ReviewableFlaggedPost, type: :model do actions = reviewable.actions_for(guardian) expect(actions.has?(:agree_and_hide)).to eq(true) expect(actions.has?(:agree_and_keep)).to eq(true) + expect(actions.has?(:agree_and_edit)).to eq(true) expect(actions.has?(:agree_and_keep_hidden)).to eq(false) expect(actions.has?(:agree_and_silence)).to eq(true) expect(actions.has?(:agree_and_suspend)).to eq(true) @@ -56,6 +57,7 @@ RSpec.describe ReviewableFlaggedPost, type: :model do post.hidden = true actions = reviewable.actions_for(guardian) expect(actions.has?(:agree_and_keep)).to eq(false) + expect(actions.has?(:agree_and_edit)).to eq(false) expect(actions.has?(:agree_and_keep_hidden)).to eq(true) end @@ -123,6 +125,13 @@ RSpec.describe ReviewableFlaggedPost, type: :model do expect(post).not_to be_hidden end + it "agree_and_keep agrees with the flags and edits the post" do + reviewable.perform(moderator, :agree_and_keep) + expect(reviewable).to be_approved + expect(score.reload).to be_agreed + expect(post).not_to be_hidden + end + describe "with reviewable claiming enabled" do fab!(:claimed) { Fabricate(:reviewable_claimed_topic, topic: post.topic, user: moderator) } it "clears the claimed topic on resolve" do diff --git a/spec/system/reviewables_spec.rb b/spec/system/reviewables_spec.rb index 2931ae56594..12bc3bcc2bb 100644 --- a/spec/system/reviewables_spec.rb +++ b/spec/system/reviewables_spec.rb @@ -5,6 +5,8 @@ describe "Reviewables", type: :system do fab!(:admin) fab!(:theme) fab!(:long_post) { Fabricate(:post_with_very_long_raw_content) } + fab!(:post) + let(:composer) { PageObjects::Components::Composer.new } before { sign_in(admin) } @@ -23,13 +25,36 @@ describe "Reviewables", type: :system do end describe "when there is a flagged post reviewable with a short post" do - fab!(:short_reviewable) { Fabricate(:reviewable_flagged_post) } + fab!(:short_reviewable) { Fabricate(:reviewable_flagged_post, target: post) } it "should not show a button to expand/collapse the post content" do visit("/review") expect(review_page).to have_no_post_body_collapsed expect(review_page).to have_no_post_body_toggle end + + describe "reviewable actions" do + it "should have agree_and_edit action" do + visit("/review") + select_kit = + PageObjects::Components::SelectKit.new(".dropdown-select-box.post-agree-and-hide") + select_kit.expand + + expect(page).to have_selector("[data-value='post-agree_and_edit']") + end + + it "agree_and_edit should open the composer" do + visit("/review") + select_kit = + PageObjects::Components::SelectKit.new(".dropdown-select-box.post-agree-and-hide") + select_kit.expand + + find("[data-value='post-agree_and_edit']").click + + expect(composer).to be_opened + expect(composer.composer_input.value).to eq(post.raw) + end + end end describe "when there is a queued post reviewable with a short post" do