DEV: APIs for plugin to add custom reviewable confirm modal (#12246)

This commit is contained in:
Mark VanLandingham 2021-03-02 10:28:27 -06:00 committed by GitHub
parent 4c1e02d412
commit 4adce0d844
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 6 deletions

View File

@ -12,6 +12,14 @@ import showModal from "discourse/lib/show-modal";
let _components = {};
const pluginReviewableParams = {};
export function addPluginReviewableParam(reviewableType, param) {
pluginReviewableParams[reviewableType]
? pluginReviewableParams[reviewableType].push(param)
: (pluginReviewableParams[reviewableType] = [param]);
}
export default Component.extend({
adminTools: optionalService(),
tagName: "",
@ -106,14 +114,23 @@ export default Component.extend({
let performAction = () => {
let version = reviewable.get("version");
this.set("updating", true);
const data = {
send_email: reviewable.sendEmail,
reject_reason: reviewable.rejectReason,
};
(pluginReviewableParams[reviewable.type] || []).forEach((param) => {
if (reviewable[param]) {
data[param] = reviewable[param];
}
});
return ajax(
`/review/${reviewable.id}/perform/${action.id}?version=${version}`,
{
type: "PUT",
data: {
send_email: reviewable.sendEmail,
reject_reason: reviewable.rejectReason,
},
data,
}
)
.then((result) => {
@ -227,6 +244,7 @@ export default Component.extend({
let msg = action.get("confirm_message");
let requireRejectReason = action.get("require_reject_reason");
let customModal = action.get("custom_modal");
if (msg) {
bootbox.confirm(msg, (answer) => {
if (answer) {
@ -241,6 +259,14 @@ export default Component.extend({
performConfirmed: this._performConfirmed.bind(this),
action,
});
} else if (customModal) {
showModal(customModal, {
title: `review.${customModal}.title`,
model: this.reviewable,
}).setProperties({
performConfirmed: this._performConfirmed.bind(this),
action,
});
} else {
return this._performConfirmed(action);
}

View File

@ -44,6 +44,7 @@ import { addGTMPageChangedCallback } from "discourse/lib/page-tracker";
import { addGlobalNotice } from "discourse/components/global-notice";
import { addNavItem } from "discourse/models/nav-item";
import { addPluginOutletDecorator } from "discourse/components/plugin-connector";
import { addPluginReviewableParam } from "discourse/components/reviewable-item";
import { addPopupMenuOptionsCallback } from "discourse/controllers/composer";
import { addPostClassesCallback } from "discourse/widgets/post";
import { addPostSmallActionIcon } from "discourse/widgets/post-small-action";
@ -1222,6 +1223,9 @@ class PluginApi {
addSaveableUserOptionField(fieldName) {
addSaveableUserOptionField(fieldName);
}
addPluginReviewableParam(reviewableType, param) {
addPluginReviewableParam(reviewableType, param);
}
/**
* Change the default category background and text colors in the

View File

@ -192,6 +192,11 @@ class ReviewablesController < ApplicationController
args.merge!(reject_reason: params[:reject_reason], send_email: params[:send_email] != "false") if reviewable.type == 'ReviewableUser'
plugin_params = DiscoursePluginRegistry.reviewable_params.select do |reviewable_param|
reviewable.type == reviewable_param[:type].to_s.classify
end
args.merge!(params.slice(*plugin_params.map { |pp| pp[:param] }).permit!)
result = reviewable.perform(current_user, params[:action_id].to_sym, args)
rescue Reviewable::InvalidAction => e
# Consider InvalidAction an InvalidAccess

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class ReviewableActionSerializer < ApplicationSerializer
attributes :id, :icon, :button_class, :label, :confirm_message, :description, :client_action, :require_reject_reason
attributes :id, :icon, :button_class, :label, :confirm_message, :description, :client_action, :require_reject_reason, :custom_modal
def label
I18n.t(object.label)
@ -30,4 +30,8 @@ class ReviewableActionSerializer < ApplicationSerializer
def include_require_reject_reason?
object.require_reject_reason.present?
end
def include_custom_modal?
object.custom_modal.present?
end
end

View File

@ -84,6 +84,7 @@ class DiscoursePluginRegistry
define_filtered_register :user_api_key_scope_mappings
define_filtered_register :permitted_bulk_action_parameters
define_filtered_register :reviewable_params
def self.register_auth_provider(auth_provider)
self.auth_providers << auth_provider

View File

@ -877,6 +877,13 @@ class Plugin::Instance
DiscoursePluginRegistry.demon_processes << demon_class
end
def add_permitted_reviewable_param(type, param)
DiscoursePluginRegistry.register_reviewable_param({
type: type,
param: param
}, self)
end
protected
def self.js_path

View File

@ -33,7 +33,7 @@ class Reviewable < ActiveRecord::Base
end
class Action < Item
attr_accessor :icon, :button_class, :label, :description, :confirm_message, :client_action, :require_reject_reason
attr_accessor :icon, :button_class, :label, :description, :confirm_message, :client_action, :require_reject_reason, :custom_modal
def initialize(id, icon = nil, button_class = nil, label = nil)
super(id)

View File

@ -432,6 +432,48 @@ describe ReviewablesController do
end
end
describe "with reviewable params added via plugin API" do
class ::ReviewablePhony < Reviewable
def build_actions(actions, guardian, _args)
return [] unless pending?
actions.add(:approve_phony) do |action|
action.label = "js.phony.review.approve"
end
end
def perform_approve_phony(performed_by, args)
puts args.inspect
MessageBus.publish("/phony-reviewable-test", { args: args }, user_ids: [1])
create_result(:success, :approved)
end
end
before do
plugin = Plugin::Instance.new
plugin.add_permitted_reviewable_param(:reviewable_phony, :fake_id)
end
after do
DiscoursePluginRegistry.reset!
end
fab!(:reviewable_phony) { Fabricate(:reviewable, type: "ReviewablePhony") }
it "passes the added param into the reviewable class' perform method" do
MessageBus.expects(:publish)
.with("/phony-reviewable-test", { args: {
version: reviewable_phony.version,
"fake_id" => "2" }
},
{ user_ids: [1] })
.once
put "/review/#{reviewable_phony.id}/perform/approve_phony.json?version=#{reviewable_phony.version}", params: { fake_id: 2 }
expect(response.status).to eq(200)
end
end
context "#topics" do
fab!(:post0) { Fabricate(:post) }
fab!(:post1) { Fabricate(:post, topic: post0.topic) }