From 5770ba1a6434800858bb7de53444f8140eff23f2 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Thu, 29 Feb 2024 17:55:46 +0100 Subject: [PATCH] fix(mentions): parse groups and federated user mentions Signed-off-by: Maksim Sukharev --- .../EditableTextField.vue | 2 +- .../MessageButtonsBar/MessageButtonsBar.vue | 2 +- src/components/NewMessage/NewMessage.vue | 2 +- src/stores/chatExtras.js | 2 +- src/types/index.ts | 27 ++++++++++++ src/utils/{textParse.js => textParse.ts} | 44 +++++++++++-------- 6 files changed, 57 insertions(+), 22 deletions(-) rename src/utils/{textParse.js => textParse.ts} (57%) diff --git a/src/components/ConversationSettings/EditableTextField.vue b/src/components/ConversationSettings/EditableTextField.vue index 42b72f5aadbc..afb151d9e181 100644 --- a/src/components/ConversationSettings/EditableTextField.vue +++ b/src/components/ConversationSettings/EditableTextField.vue @@ -87,7 +87,7 @@ import NcRichContenteditable from '@nextcloud/vue/dist/Components/NcRichContente import NcRichText from '@nextcloud/vue/dist/Components/NcRichText.js' import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js' -import { parseSpecialSymbols } from '../../utils/textParse.js' +import { parseSpecialSymbols } from '../../utils/textParse.ts' export default { name: 'EditableTextField', diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue index 1a6afb33da7c..bb3a1fb6d56d 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue @@ -307,7 +307,7 @@ import { getMessageReminder, removeMessageReminder, setMessageReminder } from '. import { copyConversationLinkToClipboard } from '../../../../../services/urlService.js' import { useIntegrationsStore } from '../../../../../stores/integrations.js' import { useReactionsStore } from '../../../../../stores/reactions.js' -import { parseMentions } from '../../../../../utils/textParse.js' +import { parseMentions } from '../../../../../utils/textParse.ts' const EmojiIndex = new EmojiIndexFactory(data) const supportReminders = getCapabilities()?.spreed?.features?.includes('remind-me-later') diff --git a/src/components/NewMessage/NewMessage.vue b/src/components/NewMessage/NewMessage.vue index 35df83113849..fee93892da46 100644 --- a/src/components/NewMessage/NewMessage.vue +++ b/src/components/NewMessage/NewMessage.vue @@ -226,7 +226,7 @@ import { useChatExtrasStore } from '../../stores/chatExtras.js' import { useSettingsStore } from '../../stores/settings.js' import { fetchClipboardContent } from '../../utils/clipboard.js' import { isDarkTheme } from '../../utils/isDarkTheme.js' -import { parseSpecialSymbols } from '../../utils/textParse.js' +import { parseSpecialSymbols } from '../../utils/textParse.ts' const disableKeyboardShortcuts = OCP.Accessibility.disableKeyboardShortcuts() const supportTypingStatus = getCapabilities()?.spreed?.config?.chat?.['typing-privacy'] !== undefined diff --git a/src/stores/chatExtras.js b/src/stores/chatExtras.js index 1d43b09688a6..83acceb37194 100644 --- a/src/stores/chatExtras.js +++ b/src/stores/chatExtras.js @@ -26,7 +26,7 @@ import Vue from 'vue' import { EventBus } from '../services/EventBus.js' import { getUserAbsence } from '../services/participantsService.js' -import { parseSpecialSymbols, parseMentions } from '../utils/textParse.js' +import { parseSpecialSymbols, parseMentions } from '../utils/textParse.ts' /** * @typedef {string} Token diff --git a/src/types/index.ts b/src/types/index.ts index 6061db30b8f6..79a45fb4459e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -6,6 +6,33 @@ type ApiResponse = Promise<{ data: T }> // Conversations export type Conversation = components['schemas']['Room'] +// Chats +type ParamObject = { + id: string, + name: string, + type: string, +} +export type Mention = ParamObject & { + server?: string, + 'call-type'?: string, + 'icon-url'?: string, +} +type File = ParamObject & { + 'size': number, + 'path': string, + 'link': string, + 'etag': string, + 'permissions': number, + 'mimetype': string, + 'preview-available': string, + 'width': number, + 'height': number, +} +type MessageParameters = Record +export type ChatMessage = Omit & { + messageParameters: MessageParameters +} + // Bots export type Bot = components['schemas']['Bot'] export type BotWithDetails = components['schemas']['BotWithDetails'] diff --git a/src/utils/textParse.js b/src/utils/textParse.ts similarity index 57% rename from src/utils/textParse.js rename to src/utils/textParse.ts index f13ef02155f8..3c039c4dc45f 100644 --- a/src/utils/textParse.js +++ b/src/utils/textParse.ts @@ -21,25 +21,34 @@ * */ +import { getBaseUrl } from '@nextcloud/router' + +import type { ChatMessage, Mention } from '../types' + /** * Parse message text to return proper formatting for mentions * - * @param {string} text The string to parse - * @param {object} parameters The parameters that contain the mentions - * @return {string} + * @param text The string to parse + * @param parameters The parameters that contain the mentions */ -function parseMentions(text, parameters) { - if (Object.keys(parameters).some(key => key.startsWith('mention'))) { - for (const [key, value] of Object.entries(parameters)) { - let mention = '' - if (value?.type === 'call') { - mention = '@all' - } else if (value?.type === 'user') { - mention = value.id.includes(' ') ? `@"${value.id}"` : `@${value.id}` - } - if (mention) { - text = text.replace(new RegExp(`{${key}}`, 'g'), mention) - } +function parseMentions(text: string, parameters: ChatMessage['messageParameters']): string { + for (const key of Object.keys(parameters).filter(key => key.startsWith('mention'))) { + const value: Mention = parameters[key] + let mention = '' + + if (key.startsWith('mention-call') && value.type === 'call') { + mention = '@all' + } else if (key.startsWith('mention-federated-user') && value.type === 'user') { + const server = value?.server ?? getBaseUrl().replace('https://', '') + mention = `@"federated_user/${value.id}@${server}"` + } else if (key.startsWith('mention-group') && value.type === 'user-group') { + mention = `@"group/${value.id}"` + } else if (key.startsWith('mention-user') && value.type === 'user') { + mention = value.id.includes(' ') ? `@"${value.id}"` : `@${value.id}` + } + + if (mention) { + text = text.replace(new RegExp(`{${key}}`, 'g'), mention) } } return text @@ -49,10 +58,9 @@ function parseMentions(text, parameters) { * Parse special symbols in text like & < > § * FIXME upstream: https://github.com/nextcloud-libraries/nextcloud-vue/issues/4492 * - * @param {string} text The string to parse - * @return {string} + * @param text The string to parse */ -function parseSpecialSymbols(text) { +function parseSpecialSymbols(text: string): string { const temp = document.createElement('textarea') temp.innerHTML = text.replace(/&/gmi, '&') text = temp.value.replace(/&/gmi, '&').replace(/</gmi, '<')