DEV: Allow `freeze_original` argument in topics controller & JS transformer (#30120)

PostMover has a new option called freeze_original implemented in this commit. It was previously unexposed in the controller. This PR permits the param in the controller, and passes it into PostMover.

Also, this applies a value transformer for move/merge payload options. In addition a plugin outlet in the move post modal. This allows plugins to add content to the modal, which can modify the payload (and use the freeze_original argument for example)
This commit is contained in:
Mark VanLandingham 2024-12-05 08:31:05 -06:00 committed by GitHub
parent 555ca4da55
commit 68e57190df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 101 additions and 0 deletions

View File

@ -131,6 +131,8 @@
{{/if}} {{/if}}
</div> </div>
<PluginOutlet @name="move-to-topic-after-radio-buttons" />
{{#if this.existingTopic}} {{#if this.existingTopic}}
<p> <p>
{{html-safe {{html-safe

View File

@ -3,6 +3,7 @@ import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { applyValueTransformer } from "discourse/lib/transformer";
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import { mergeTopic, movePosts } from "discourse/models/topic"; import { mergeTopic, movePosts } from "discourse/models/topic";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
@ -145,6 +146,15 @@ export default class MoveToTopic extends Component {
}; };
} }
mergeOptions = applyValueTransformer(
"move-to-topic-merge-options",
mergeOptions
);
moveOptions = applyValueTransformer(
"move-to-topic-move-options",
moveOptions
);
try { try {
let result; let result;
if (this.args.model.selectedAllPosts) { if (this.args.model.selectedAllPosts) {

View File

@ -13,6 +13,8 @@ export const VALUE_TRANSFORMERS = Object.freeze([
"invite-simple-mode-topic", "invite-simple-mode-topic",
"mentions-class", "mentions-class",
"more-topics-tabs", "more-topics-tabs",
"move-to-topic-merge-options",
"move-to-topic-move-options",
"parent-category-row-class-mobile", "parent-category-row-class-mobile",
"parent-category-row-class", "parent-category-row-class",
"post-menu-buttons", "post-menu-buttons",

View File

@ -0,0 +1,49 @@
import { click, fillIn, visit } from "@ember/test-helpers";
import { test } from "qunit";
import { withPluginApi } from "discourse/lib/plugin-api";
import pretender, {
parsePostData,
response,
} from "discourse/tests/helpers/create-pretender";
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
acceptance("Modal - move-to-topic", function (needs) {
needs.user({ admin: true });
test("Transformer can modify merge/move options sent in request", async function (assert) {
withPluginApi("1.24.0", (api) => {
["move-to-topic-merge-options", "move-to-topic-move-options"].forEach(
(transformerName) => {
api.registerValueTransformer(transformerName, (transformer) => {
transformer.value.sillyVal = true;
return transformer.value;
});
}
);
});
await visit("/t/internationalization-localization/280");
// Open admin menu, select a post, and open move to topic modal
await click(".topic-admin-menu-trigger");
await click(".topic-admin-menu-content .topic-admin-multi-select button");
await click(".select-posts .select-post");
await click(".selected-posts .move-to-topic");
// Choose existing topic, and pick the first topic.
await click("input#move-to-existing-topic");
await fillIn("input#choose-topic-title", 1);
await click(".choose-topic-list .existing-topic input");
pretender.post("/t/280/move-posts", (request) => {
assert.step("request");
const data = parsePostData(request.requestBody);
assert.strictEqual(data.sillyVal, "true");
return response({ success: true });
});
// Submit!
await click(".d-modal__footer .btn-primary");
assert.verifySteps(["request"]);
});
});

View File

@ -857,6 +857,7 @@ class TopicsController < ApplicationController
params.permit(:participants) params.permit(:participants)
params.permit(:chronological_order) params.permit(:chronological_order)
params.permit(:archetype) params.permit(:archetype)
params.permit(:freeze_original)
raise Discourse::InvalidAccess if params[:archetype] == "private_message" && !guardian.is_staff? raise Discourse::InvalidAccess if params[:archetype] == "private_message" && !guardian.is_staff?
@ -869,6 +870,7 @@ class TopicsController < ApplicationController
args = {} args = {}
args[:destination_topic_id] = destination_topic_id.to_i args[:destination_topic_id] = destination_topic_id.to_i
args[:chronological_order] = params[:chronological_order] == "true" args[:chronological_order] = params[:chronological_order] == "true"
args[:freeze_original] = params[:freeze_original] == "true"
if params[:archetype].present? if params[:archetype].present?
args[:archetype] = params[:archetype] args[:archetype] = params[:archetype]
@ -891,6 +893,7 @@ class TopicsController < ApplicationController
params.permit(:participants) params.permit(:participants)
params.permit(:chronological_order) params.permit(:chronological_order)
params.permit(:archetype) params.permit(:archetype)
params.permit(:freeze_original)
topic = Topic.with_deleted.find_by(id: topic_id) topic = Topic.with_deleted.find_by(id: topic_id)
guardian.ensure_can_move_posts!(topic) guardian.ensure_can_move_posts!(topic)
@ -1399,6 +1402,7 @@ class TopicsController < ApplicationController
].present? ].present?
args[:tags] = params[:tags] if params[:tags].present? args[:tags] = params[:tags] if params[:tags].present?
args[:chronological_order] = params[:chronological_order] == "true" args[:chronological_order] = params[:chronological_order] == "true"
args[:freeze_original] = true if params[:freeze_original] == "true"
if params[:archetype].present? if params[:archetype].present?
args[:archetype] = params[:archetype] args[:archetype] = params[:archetype]

View File

@ -1298,6 +1298,9 @@ class Topic < ActiveRecord::Base
moved_by, moved_by,
post_ids, post_ids,
move_to_pm: opts[:archetype].present? && opts[:archetype] == "private_message", move_to_pm: opts[:archetype].present? && opts[:archetype] == "private_message",
options: {
freeze_original: opts[:freeze_original],
},
) )
if opts[:destination_topic_id] if opts[:destination_topic_id]

View File

@ -166,6 +166,21 @@ RSpec.describe TopicsController do
expect(Tag.all.pluck(:name)).to include("foo", "bar") expect(Tag.all.pluck(:name)).to include("foo", "bar")
end end
describe "with freeze_original param" do
it "duplicates post to new topic and keeps original post in place" do
expect do
post "/t/#{topic.id}/move-posts.json",
params: {
title: "Logan is a good movie",
post_ids: [p2.id],
freeze_original: true,
}
end.to change { Topic.count }.by(1)
expect(response.status).to eq(200)
expect(topic.post_ids).to include(p2.id)
end
end
describe "when topic has been deleted" do describe "when topic has been deleted" do
it "should still be able to move posts" do it "should still be able to move posts" do
PostDestroyer.new(admin, topic.first_post).destroy PostDestroyer.new(admin, topic.first_post).destroy
@ -308,6 +323,22 @@ RSpec.describe TopicsController do
expect(result["url"]).to be_present expect(result["url"]).to be_present
end end
describe "with freeze_original param" do
it "duplicates post to topic and keeps original post in place" do
expect do
post "/t/#{topic.id}/move-posts.json",
params: {
post_ids: [p2.id],
destination_topic_id: dest_topic.id,
freeze_original: true,
}
end.to change { dest_topic.posts.count }.by(1)
expect(response.status).to eq(200)
expect(topic.post_ids).to include(p2.id)
expect(dest_topic.posts.find_by(raw: p2.raw)).to be_present
end
end
it "triggers an event on merge" do it "triggers an event on merge" do
begin begin
called = false called = false