DEV: only supports headings in messages for bots (#29585)

The markdown it rule "heading" will only be used when the message is done by a bot, which means an id < 0.

This commit also adds a is-bot css class on messages made by a bot, for finer control.

---------

Co-authored-by: Martin Brennan <mjrbrennan@gmail.com>
This commit is contained in:
Joffrey JAFFEUX
2024-11-07 22:27:35 +09:00
committed by GitHub
parent 193d25df00
commit 5010fced92
4 changed files with 44 additions and 19 deletions

View File

@ -220,10 +220,12 @@ module Chat
blockquote blockquote
emphasis emphasis
replacements replacements
heading
] ]
def self.cook(message, opts = {}) def self.cook(message, opts = {})
rules = MARKDOWN_IT_RULES
rules << "heading" if opts[:user_id] && opts[:user_id].negative?
# A rule in our Markdown pipeline may have Guardian checks that require a # A rule in our Markdown pipeline may have Guardian checks that require a
# user to be present. The last editing user of the message will be more # user to be present. The last editing user of the message will be more
# generally up to date than the creating user. For example, we use # generally up to date than the creating user. For example, we use
@ -235,7 +237,7 @@ module Chat
message, message,
features_override: features_override:
MARKDOWN_FEATURES + DiscoursePluginRegistry.chat_markdown_features.to_a, MARKDOWN_FEATURES + DiscoursePluginRegistry.chat_markdown_features.to_a,
markdown_it_rules: MARKDOWN_IT_RULES, markdown_it_rules: rules,
force_quote_link: true, force_quote_link: true,
user_id: opts[:user_id], user_id: opts[:user_id],
hashtag_context: "chat-composer", hashtag_context: "chat-composer",

View File

@ -11,7 +11,7 @@ import willDestroy from "@ember/render-modifiers/modifiers/will-destroy";
import { cancel, schedule } from "@ember/runloop"; import { cancel, schedule } from "@ember/runloop";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { modifier } from "ember-modifier"; import { modifier } from "ember-modifier";
import { eq, not } from "truth-helpers"; import { eq, lt, not } from "truth-helpers";
import DButton from "discourse/components/d-button"; import DButton from "discourse/components/d-button";
import concatClass from "discourse/helpers/concat-class"; import concatClass from "discourse/helpers/concat-class";
import { applyValueTransformer } from "discourse/lib/transformer"; import { applyValueTransformer } from "discourse/lib/transformer";
@ -547,6 +547,7 @@ export default class ChatMessage extends Component {
(if this.pane.selectingMessages "-selectable") (if this.pane.selectingMessages "-selectable")
(if @message.highlighted "-highlighted") (if @message.highlighted "-highlighted")
(if @message.streaming "-streaming") (if @message.streaming "-streaming")
(if (lt @message.user.id 0) "is-bot")
(if (eq @message.user.id this.currentUser.id) "is-by-current-user") (if (eq @message.user.id this.currentUser.id) "is-by-current-user")
(if (eq @message.id this.currentUser.id) "is-by-current-user") (if (eq @message.id this.currentUser.id) "is-by-current-user")
(if (if

View File

@ -79,23 +79,33 @@ describe Chat::Message do
HTML HTML
end end
it "supports headings" do context "when message is made by a bot user" do
cooked = described_class.cook <<~MD it "supports headings" do
# h1 cooked = described_class.cook(<<~MD, user_id: -1)
## h2 # h1
### h3 ## h2
#### h4 ### h3
##### h5 #### h4
###### h6 ##### h5
MD ###### h6
MD
expect(cooked).to match_html <<~HTML
<h1><a name="h1-1" class="anchor" href="#h1-1"></a>h1</h1>
<h2><a name="h2-2" class="anchor" href="#h2-2"></a>h2</h2>
<h3><a name="h3-3" class="anchor" href="#h3-3"></a>h3</h3>
<h4><a name="h4-4" class="anchor" href="#h4-4"></a>h4</h4>
<h5><a name="h5-5" class="anchor" href="#h5-5"></a>h5</h5>
<h6><a name="h6-6" class="anchor" href="#h6-6"></a>h6</h6>
HTML
end
end
it "doesn't support headings" do
cooked = described_class.cook("# test")
expect(cooked).to match_html <<~HTML expect(cooked).to match_html <<~HTML
<h1><a name="h1-1" class="anchor" href="#h1-1"></a>h1</h1> <p># test</p>
<h2><a name="h2-2" class="anchor" href="#h2-2"></a>h2</h2>
<h3><a name="h3-3" class="anchor" href="#h3-3"></a>h3</h3>
<h4><a name="h4-4" class="anchor" href="#h4-4"></a>h4</h4>
<h5><a name="h5-5" class="anchor" href="#h5-5"></a>h5</h5>
<h6><a name="h6-6" class="anchor" href="#h6-6"></a>h6</h6>
HTML HTML
end end

View File

@ -2,6 +2,7 @@ import { getOwner } from "@ember/owner";
import { clearRender, render } from "@ember/test-helpers"; import { clearRender, render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile"; import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit"; import { module, test } from "qunit";
import CoreFabricators from "discourse/lib/fabricators";
import { setupRenderingTest } from "discourse/tests/helpers/component-test"; import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { exists, query } from "discourse/tests/helpers/qunit-helpers"; import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators"; import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
@ -47,7 +48,18 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
); );
}); });
test("message with mark html tag", async function (assert) { test("Message by a bot", async function (assert) {
this.message = new ChatFabricators(getOwner(this)).message({
message: "what <mark>test</mark>",
user: new CoreFabricators(getOwner(this)).user({ id: -10 }),
});
await this.message.cook();
await render(template);
assert.dom(".chat-message-container.is-bot").exists("has the bot class");
});
test("Message with mark html tag", async function (assert) {
this.message = new ChatFabricators(getOwner(this)).message({ this.message = new ChatFabricators(getOwner(this)).message({
message: "what <mark>test</mark>", message: "what <mark>test</mark>",
}); });