Skip to content

Commit

Permalink
fix(mentions): parse groups and federated user mentions
Browse files Browse the repository at this point in the history
Signed-off-by: Maksim Sukharev <[email protected]>
  • Loading branch information
Antreesy committed Feb 29, 2024
1 parent 10e6562 commit 5770ba1
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/components/ConversationSettings/EditableTextField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
2 changes: 1 addition & 1 deletion src/components/NewMessage/NewMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/stores/chatExtras.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,33 @@ type ApiResponse<T> = 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<string, ParamObject | Mention | File>
export type ChatMessage = Omit<components['schemas']['ChatMessage'], 'messageParameters'> & {
messageParameters: MessageParameters
}

// Bots
export type Bot = components['schemas']['Bot']
export type BotWithDetails = components['schemas']['BotWithDetails']
Expand Down
44 changes: 26 additions & 18 deletions src/utils/textParse.js → src/utils/textParse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -49,10 +58,9 @@ function parseMentions(text, parameters) {
* Parse special symbols in text like &amp; &lt; &gt; &sect;
* 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, '&amp;')
text = temp.value.replace(/&amp;/gmi, '&').replace(/&lt;/gmi, '<')
Expand Down

0 comments on commit 5770ba1

Please sign in to comment.