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}}
</div>
<PluginOutlet @name="move-to-topic-after-radio-buttons" />
{{#if this.existingTopic}}
<p>
{{html-safe

View File

@ -3,6 +3,7 @@ import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import { applyValueTransformer } from "discourse/lib/transformer";
import DiscourseURL from "discourse/lib/url";
import { mergeTopic, movePosts } from "discourse/models/topic";
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 {
let result;
if (this.args.model.selectedAllPosts) {

View File

@ -13,6 +13,8 @@ export const VALUE_TRANSFORMERS = Object.freeze([
"invite-simple-mode-topic",
"mentions-class",
"more-topics-tabs",
"move-to-topic-merge-options",
"move-to-topic-move-options",
"parent-category-row-class-mobile",
"parent-category-row-class",
"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(:chronological_order)
params.permit(:archetype)
params.permit(:freeze_original)
raise Discourse::InvalidAccess if params[:archetype] == "private_message" && !guardian.is_staff?
@ -869,6 +870,7 @@ class TopicsController < ApplicationController
args = {}
args[:destination_topic_id] = destination_topic_id.to_i
args[:chronological_order] = params[:chronological_order] == "true"
args[:freeze_original] = params[:freeze_original] == "true"
if params[:archetype].present?
args[:archetype] = params[:archetype]
@ -891,6 +893,7 @@ class TopicsController < ApplicationController
params.permit(:participants)
params.permit(:chronological_order)
params.permit(:archetype)
params.permit(:freeze_original)
topic = Topic.with_deleted.find_by(id: topic_id)
guardian.ensure_can_move_posts!(topic)
@ -1399,6 +1402,7 @@ class TopicsController < ApplicationController
].present?
args[:tags] = params[:tags] if params[:tags].present?
args[:chronological_order] = params[:chronological_order] == "true"
args[:freeze_original] = true if params[:freeze_original] == "true"
if params[:archetype].present?
args[:archetype] = params[:archetype]

View File

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

View File

@ -166,6 +166,21 @@ RSpec.describe TopicsController do
expect(Tag.all.pluck(:name)).to include("foo", "bar")
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
it "should still be able to move posts" do
PostDestroyer.new(admin, topic.first_post).destroy
@ -308,6 +323,22 @@ RSpec.describe TopicsController do
expect(result["url"]).to be_present
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
begin
called = false