MM-59854 Fully allow at mentions in message attachment field values and add E2E tests (#28018)

* Add descriptions to test cases for getNeededAtMentionedUsernames

* MM-59854 Load users who are at-mentioned in message attachment fields

* MM-59854 Add server support for at-mentioning users in message attachment fields

* Migrate support/external_commands from JS to TS

* MM-59584 Ensure that at-mentions never show in other message attachment fields

* MM-59584 Add E2E tests for how we load users based on at mentions

* Use new E2E test helpers in other places

* Update snapshots
Этот коммит содержится в:
Harrison Healey
2024-09-24 09:41:03 -04:00
коммит произвёл GitHub
родитель 3e84d20dbe
Коммит 46cad5c552
22 изменённых файлов: 503 добавлений и 198 удалений

Просмотреть файл

@@ -424,6 +424,7 @@ exports[`components/post_view/MessageAttachment should match snapshot when the a
message="Do you like https://mattermost.com?"
options={
Object {
"atMentions": false,
"autolinkedUrlSchemes": Array [],
"mentionHighlight": false,
"renderer": LinkOnlyRenderer {
@@ -469,6 +470,7 @@ exports[`components/post_view/MessageAttachment should match snapshot when the a
message="Do you like :pizza:?"
options={
Object {
"atMentions": false,
"autolinkedUrlSchemes": Array [],
"mentionHighlight": false,
"renderer": LinkOnlyRenderer {
@@ -514,6 +516,7 @@ exports[`components/post_view/MessageAttachment should match snapshot when the a
message="Don't you like emojis?"
options={
Object {
"atMentions": false,
"autolinkedUrlSchemes": Array [],
"mentionHighlight": false,
"renderer": LinkOnlyRenderer {
@@ -559,6 +562,7 @@ exports[`components/post_view/MessageAttachment should match snapshot when the f
message="footer"
options={
Object {
"atMentions": false,
"autolinkedUrlSchemes": Array [],
"mentionHighlight": false,
"renderer": LinkOnlyRenderer {
@@ -620,6 +624,7 @@ exports[`components/post_view/MessageAttachment should match value on getFieldsT
message="title_1"
options={
Object {
"atMentions": false,
"markdown": false,
"mentionHighlight": false,
}
@@ -654,6 +659,7 @@ exports[`components/post_view/MessageAttachment should match value on getFieldsT
message="title_2"
options={
Object {
"atMentions": false,
"markdown": false,
"mentionHighlight": false,
}

Просмотреть файл

@@ -232,7 +232,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
let rowPos = 0;
let lastWasLong = false;
let nrTables = 0;
const markdown = {markdown: false, mentionHighlight: false};
const markdown = {markdown: false, mentionHighlight: false, atMentions: false};
fields.forEach((field: MessageAttachmentField, i: number) => {
if (rowPos === 2 || !(field.short === true) || lastWasLong) {
@@ -421,6 +421,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
<Markdown
message={attachment.title}
options={{
atMentions: false,
mentionHighlight: false,
renderer: new LinkOnlyRenderer(),
autolinkedUrlSchemes: [],

Просмотреть файл

@@ -570,7 +570,7 @@ describe('Actions.Posts', () => {
});
});
it('getNeededAtMentionedUsernames', async () => {
describe('getNeededAtMentionedUsernames', () => {
const state = {
entities: {
users: {
@@ -592,65 +592,55 @@ describe('Actions.Posts', () => {
},
} as unknown as GlobalState;
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: 'aaa'}),
])).toEqual(
new Set(),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '@aaa'}),
])).toEqual(
new Set(),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '@zzz'}),
])).toEqual(
new Set(),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '@aaa @bbb @ccc @zzz'}),
])).toEqual(
new Set(['bbb', 'ccc']),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '@bbb. @ccc.ddd'}),
])).toEqual(
new Set(['bbb.', 'bbb', 'ccc.ddd']),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '@bbb- @ccc-ddd'}),
])).toEqual(
new Set(['bbb-', 'bbb', 'ccc-ddd']),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '@bbb_ @ccc_ddd'}),
])).toEqual(
new Set(['bbb_', 'ccc_ddd']),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '(@bbb/@ccc) ddd@eee'}),
])).toEqual(
new Set(['bbb', 'ccc']),
);
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({
const testCases = [
{
name: "shouldn't return anything when no users are at-mentioned",
input: TestHelper.getPostMock({message: 'aaa'}),
expected: new Set(),
},
{
name: "shouldn't return anything for a user that's already loaded",
input: TestHelper.getPostMock({message: '@aaa'}),
expected: new Set(),
},
{
name: "shouldn't return anything for a group that's already loaded",
input: TestHelper.getPostMock({message: '@zzz'}),
expected: new Set(),
},
{
name: 'should return any unrecognized at-mentions',
input: TestHelper.getPostMock({message: '@aaa @bbb @ccc @zzz'}),
expected: new Set(['bbb', 'ccc']),
},
{
name: 'should return at-mentions followed by period both with and without the period',
input: TestHelper.getPostMock({message: '@bbb. @ccc.ddd'}),
expected: new Set(['bbb.', 'bbb', 'ccc.ddd']),
},
{
name: 'should return at-mentions followed by hyphen both with and without the hyphen',
input: TestHelper.getPostMock({message: '@bbb- @ccc-ddd'}),
expected: new Set(['bbb-', 'bbb', 'ccc-ddd']),
},
{
name: 'should return at-mentions followed by underscores with the underscore',
input: TestHelper.getPostMock({message: '@bbb_ @ccc_ddd'}),
expected: new Set(['bbb_', 'ccc_ddd']),
},
{
name: 'should return at-mentions in brackets',
input: TestHelper.getPostMock({message: '(@bbb/@ccc)'}),
expected: new Set(['bbb', 'ccc']),
},
{
name: "shouldn't return anything when an at sign is in the middle of a word",
input: TestHelper.getPostMock({message: 'ddd@eee'}),
expected: new Set(),
},
{
name: 'should return at-mentions from inside message attachment props text and pretext',
input: TestHelper.getPostMock({
message: '@aaa @bbb',
props: {
attachments: [
@@ -659,23 +649,55 @@ describe('Actions.Posts', () => {
],
},
}),
]),
).toEqual(
new Set(['bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg']),
);
expected: new Set(['bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg']),
},
{
name: 'should return at-mentions from inside message attachment field values but not their titles',
input: TestHelper.getPostMock({
props: {
attachments: [
{
fields: [
{title: '@bbb', value: '@ccc'},
{value: '@ddd'},
],
},
{
fields: [
{title: '@eee', value: '@fff'},
{value: '@ggg'},
],
},
],
},
}),
expected: new Set(['ccc', 'ddd', 'fff', 'ggg']),
},
];
// should never try to request usernames matching special mentions
expect(
Actions.getNeededAtMentionedUsernamesAndGroups(state, [
TestHelper.getPostMock({message: '@all'}),
TestHelper.getPostMock({message: '@here'}),
TestHelper.getPostMock({message: '@channel'}),
TestHelper.getPostMock({message: '@all.'}),
TestHelper.getPostMock({message: '@here.'}),
TestHelper.getPostMock({message: '@channel.'}),
])).toEqual(
new Set(),
);
for (const specialMention of [
'@all',
'@here',
'@channel',
'@all.',
'@here.',
'@channel.',
]) {
testCases.push({
name: `should never return special mentions (${specialMention})`,
input: TestHelper.getPostMock({message: specialMention}),
expected: new Set(),
});
}
for (const testCase of testCases) {
test(testCase.name, () => {
expect(Actions.getNeededAtMentionedUsernamesAndGroups(
state,
[testCase.input],
)).toEqual(testCase.expected);
});
}
});
it('getPostsSince', async () => {

Просмотреть файл

@@ -1090,6 +1090,12 @@ export function getNeededAtMentionedUsernamesAndGroups(state: GlobalState, posts
for (const attachment of post.props.attachments) {
findNeededUsernamesAndGroups(attachment.pretext);
findNeededUsernamesAndGroups(attachment.text);
if (attachment.fields) {
for (const field of attachment.fields) {
findNeededUsernamesAndGroups(field.value);
}
}
}
}
}