From ab350f31c3199dcfcdedb49fbf89210d703a6bfe Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Fri, 31 Jan 2025 17:51:34 +0100 Subject: [PATCH 1/2] fix(textParse): refactor method and tests - wrap user mentions in double quotes Signed-off-by: Maksim Sukharev --- src/utils/__tests__/textParse.spec.js | 62 +++++++++++++++++++++++++-- src/utils/textParse.ts | 6 +-- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/utils/__tests__/textParse.spec.js b/src/utils/__tests__/textParse.spec.js index ce0d1d62876..5ff87f5c3c3 100644 --- a/src/utils/__tests__/textParse.spec.js +++ b/src/utils/__tests__/textParse.spec.js @@ -5,7 +5,7 @@ import { parseMentions, parseSpecialSymbols } from '../textParse.ts' jest.mock('@nextcloud/router', () => ({ - getBaseUrl: jest.fn().mockReturnValue('server2.com') + getBaseUrl: jest.fn().mockReturnValue('https://server2.com') })) describe('textParse', () => { @@ -38,7 +38,7 @@ describe('textParse', () => { it('replaces {mention-user} correctly', () => { const input = 'test {mention-user1} test {mention-user2}' - const output = 'test @alice test @"alice space@mail.com"' + const output = 'test @"alice" test @"alice space@mail.com"' const parameters = { 'mention-user1': { id: 'alice', @@ -72,6 +72,60 @@ describe('textParse', () => { expect(parseMentions(input, parameters)).toBe(output) }) + it('replaces {mention-team} correctly', () => { + const input = 'test {mention-team1} test {mention-team2}' + const output = 'test @"team/talk" test @"team/space talk"' + const parameters = { + 'mention-team1': { + id: 'talk', + name: 'Talk Group', + type: 'circle', + }, + 'mention-team2': { + id: 'space talk', + name: 'Out of space Talk Group', + type: 'team', + } + } + expect(parseMentions(input, parameters)).toBe(output) + }) + + it('replaces {mention-guest} correctly', () => { + const input = 'test {mention-guest1} test {mention-guest2}' + const output = 'test @"guest/abcd" test @"guest/efgh"' + const parameters = { + 'mention-guest1': { + id: 'guest/abcd', + name: 'Guest A', + type: 'guest', + }, + 'mention-guest2': { + id: 'guest/efgh', + name: 'Guest E', + type: 'guest', + } + } + expect(parseMentions(input, parameters)).toBe(output) + }) + + it('replaces {mention-email} correctly', () => { + const input = 'test {mention-email1} test {mention-email2}' + const output = 'test @"email/abcd" test @"email/efgh"' + const parameters = { + 'mention-email1': { + id: 'abcd', + name: 'Email Guest A', + type: 'email', + }, + 'mention-email2': { + id: 'efgh', + name: 'Email Guest E', + type: 'email', + } + } + expect(parseMentions(input, parameters)).toBe(output) + }) + it('replaces {mention-federated-user} correctly (for host and other federations)', () => { const input = 'test {mention-federated-user1}' const output = 'test @"federated_user/alice@server3.com"' @@ -79,8 +133,8 @@ describe('textParse', () => { 'mention-federated-user1': { id: 'alice', name: 'Feder Alice', - type: 'user', - server: 'server3.com' + type: 'federated_user', + server: 'https://server3.com' } } expect(parseMentions(input, parameters)).toBe(output) diff --git a/src/utils/textParse.ts b/src/utils/textParse.ts index badc9060b20..5e057fc8ef2 100644 --- a/src/utils/textParse.ts +++ b/src/utils/textParse.ts @@ -23,8 +23,7 @@ function parseMentions(text: string, parameters: ChatMessage['messageParameters' mention = '@all' } else if (key.startsWith('mention-federated-user') && [MENTION.TYPE.USER, MENTION.TYPE.FEDERATED_USER].includes(value.type)) { - const server = (value?.server ?? getBaseUrl()).replace('https://', '') - mention = `@"federated_user/${value.id}@${server}"` + mention = `@"federated_user/${value.id}@${(value?.server ?? getBaseUrl()).replace('https://', '')}"` } else if (key.startsWith('mention-group') && [MENTION.TYPE.USERGROUP, MENTION.TYPE.GROUP].includes(value.type)) { mention = `@"group/${value.id}"` @@ -32,11 +31,12 @@ function parseMentions(text: string, parameters: ChatMessage['messageParameters' && [MENTION.TYPE.CIRCLE, MENTION.TYPE.TEAM].includes(value.type)) { mention = `@"team/${value.id}"` } else if (key.startsWith('mention-guest') && value.type === MENTION.TYPE.GUEST) { + // id and mention-id are both prefixed with "guest/" mention = `@"${value.id}"` } else if (key.startsWith('mention-email') && value.type === MENTION.TYPE.EMAIL) { mention = `@"email/${value.id}"` } else if (key.startsWith('mention-user') && value.type === MENTION.TYPE.USER) { - mention = value.id.includes(' ') ? `@"${value.id}"` : `@${value.id}` + mention = `@"${value.id}"` } if (mention) { From 6cff3117838c82fc1cde62abd620946d8a97cceb Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Fri, 7 Feb 2025 19:49:03 +0100 Subject: [PATCH 2/2] fix(textParse): use mention id from message parameters if available Signed-off-by: Maksim Sukharev --- src/stores/__tests__/chatExtras.spec.js | 6 ++--- src/types/index.ts | 2 +- src/utils/__tests__/textParse.spec.js | 33 +++++++++++++++++++++++++ src/utils/textParse.ts | 4 ++- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/stores/__tests__/chatExtras.spec.js b/src/stores/__tests__/chatExtras.spec.js index 41af7af03fa..c61a6338b15 100644 --- a/src/stores/__tests__/chatExtras.spec.js +++ b/src/stores/__tests__/chatExtras.spec.js @@ -128,8 +128,8 @@ describe('chatExtrasStore', () => { it('should render mentions properly when editing message', () => { // Arrange const parameters = { - 'mention-call1': { type: 'call', name: 'Conversation101' }, - 'mention-user1': { type: 'user', name: 'Alice Joel', id: 'alice' }, + 'mention-call1': { type: 'call', name: 'Conversation101', 'mention-id': 'all' }, + 'mention-user1': { type: 'user', name: 'Alice Joel', id: 'alice', 'mention-id': 'alice' }, } // Act chatExtrasStore.setChatEditInput({ @@ -138,7 +138,7 @@ describe('chatExtrasStore', () => { parameters }) // Assert - expect(chatExtrasStore.getChatEditInput('token-1')).toBe('Hello @all and @alice') + expect(chatExtrasStore.getChatEditInput('token-1')).toBe('Hello @"all" and @"alice"') }) it('should store chat input without escaping special symbols', () => { diff --git a/src/types/index.ts b/src/types/index.ts index ccd704e721c..d9c38e05be8 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -127,7 +127,7 @@ export type importEmailsParams = Required // Chats -export type Mention = RichObject<'server'|'call-type'|'icon-url'> +export type Mention = RichObject<'server'|'call-type'|'icon-url'> & { 'mention-id'?: string } export type File = RichObject<'size'|'path'|'link'|'mimetype'|'preview-available'> & { 'etag': string, 'permissions': string, diff --git a/src/utils/__tests__/textParse.spec.js b/src/utils/__tests__/textParse.spec.js index 5ff87f5c3c3..57bcf867f47 100644 --- a/src/utils/__tests__/textParse.spec.js +++ b/src/utils/__tests__/textParse.spec.js @@ -10,6 +10,39 @@ jest.mock('@nextcloud/router', () => ({ describe('textParse', () => { describe('parseMentions', () => { + it('replaces mentions correctly if mention-id is available', () => { + const input = 'test {mention-call1} test {mention-user1} test {mention-group1} test {mention-federated-user1}' + const output = 'test @"all" test @"alice" test @"group/talk" test @"federated_user/alice@server2.com"' + const parameters = { + 'mention-call1': { + id: 'room-id', + name: 'Room Display Name', + type: 'call', + 'mention-id': 'all', + }, + 'mention-user1': { + id: 'alice', + name: 'Just Alice', + type: 'user', + 'mention-id': 'alice', + }, + 'mention-group1': { + id: 'talk', + name: 'Talk Group', + type: 'user-group', + 'mention-id': 'group/talk', + }, + 'mention-federated-user1': { + id: 'alice', + name: 'Feder Alice', + type: 'user', + server: 'https://server2.com', + 'mention-id': 'federated_user/alice@server2.com', + } + } + expect(parseMentions(input, parameters)).toBe(output) + }) + it('replaces {mention-call} correctly', () => { const input = 'test {mention-call1}' const output = 'test @all' diff --git a/src/utils/textParse.ts b/src/utils/textParse.ts index 5e057fc8ef2..60be51d8794 100644 --- a/src/utils/textParse.ts +++ b/src/utils/textParse.ts @@ -19,7 +19,9 @@ function parseMentions(text: string, parameters: ChatMessage['messageParameters' const value: Mention = parameters[key] as Mention let mention = '' - if (key.startsWith('mention-call') && value.type === MENTION.TYPE.CALL) { + if (value['mention-id']) { + mention = `@"${value['mention-id']}"` + } else if (key.startsWith('mention-call') && value.type === MENTION.TYPE.CALL) { mention = '@all' } else if (key.startsWith('mention-federated-user') && [MENTION.TYPE.USER, MENTION.TYPE.FEDERATED_USER].includes(value.type)) {