diff --git a/src/handlers/messages.ts b/src/handlers/messages.ts index ae20e80..f9bc89d 100644 --- a/src/handlers/messages.ts +++ b/src/handlers/messages.ts @@ -10,7 +10,11 @@ import { getUserMappingByName, save, } from '../helpers/storage' -import { axios, formatUserSessionOptions } from '../helpers/synapse' +import { + axios, + formatUserSessionOptions, + getDomainName, +} from '../helpers/synapse' import reactionKeys from '../reactions.json' import { executeAndHandleMissingMember } from './rooms' import { AxiosError } from 'axios' @@ -22,6 +26,24 @@ if (!applicationServiceToken) { throw new Error(message) } +export type Md = { + type: string + language?: string + value: { + type: string + value: string + }[] +}[] + +export type Attachements = { + text: string + md?: Md + message_link?: string + author_name?: string + author_icon?: string + type?: string +}[] + /** * Type of Rocket.Chat messages */ @@ -53,14 +75,8 @@ export type RcMessage = { usernames: string[] } } - md?: { - type: string - language?: string - value: { - type: string - value: string - }[] - }[] + md?: Md + attachments?: Attachements } /** @@ -81,8 +97,8 @@ export type MatrixMessage = { 'm.mentions'?: { user_ids: string[] } - 'format'?: string - 'formatted_body'?: string + format?: string + formatted_body?: string } /** @@ -228,18 +244,119 @@ export async function handleReactions( } } +/** + * format message body to handle Links + * @param formatted_body, matrixMessage + */ +export async function formatLink(formatted_body: string): Promise { + const regexMessageId: RegExp = /\[ \]\(https:\/[^?]+\?msg=([^)]+)\)/ + let msgMatrixId: string = '' + let messageMatrixId: string = '' + + const match: RegExpExecArray | null = regexMessageId.exec(formatted_body) + if (match && match[1]) { + const msgId: string = match[1] + log.warn(msgId) + const msgMatrixId = await getMessageId(msgId) + if (msgMatrixId) { + messageMatrixId = msgMatrixId + log.debug(`message matrix id ${messageMatrixId}`) + } + } else { + log.warn('No message ID found') + } + return [formatted_body, messageMatrixId] +} + +/** + * get text and author from linked message and compute new formatted body + * @param formatted_body, attachments + */ +export async function getFromAttachement( + formatted_body: string, + attachements: Attachements, + matrixMessage: MatrixMessage +): Promise { + const regexMessageId: RegExp = /\[ \]\(https:\/[^?]+\?msg=([^)]+)\)/ + const regexUserName: RegExp = /\/avatar\/([^?]+)/ + let authorMatrixId: string = '' + let message: string = '' + for (const item of attachements) { + if (item.message_link && item.author_icon && item.text) { + const match: RegExpExecArray | null = regexUserName.exec(item.author_icon) + if (match && match[1]) { + const username: string = match[1] + log.warn(username) + const userMapping = await getUserMappingByName(username) + if (!userMapping || !userMapping.matrixId) { + log.warn(`Could not find user mapping for name: ${username}`) + } else { + log.warn(userMapping.matrixId) + authorMatrixId = userMapping.matrixId + } + } else { + log.warn('No message ID found') + } + const textInside: string = item.text.replace(regexMessageId, '') + message = textInside + break + } + } + return [authorMatrixId, formatted_body, message] +} + +/** + * format message body to handle code + * @param formatted_body, matrixMessage + */ +export function formatCode( + formatted_body: string, + matrixMessage: MatrixMessage +): string { + let concat: string = '' + const substrings = formatted_body.split('```') + for (let i = 0; i < substrings.length; i++) { + if (i !== 0 && i !== substrings.length - 1) { + if (substrings[i].startsWith('\n')) { + substrings[i] = substrings[i].substring(1) + } + if (substrings[i].endsWith('\n')) { + substrings[i] = substrings[i].substring(0, substrings[i].length - 1) + } + substrings[i] = '
' + substrings[i] + '
' + } + if (substrings.length === 2) { + substrings[1] = '
' + substrings[1] + '
' + } + concat = concat + substrings[i] + } + if (concat !== formatted_body) { + matrixMessage.formatted_body = concat + matrixMessage.format = `org.matrix.custom.html` + } + return concat +} -export function replaceFirstTripleBackticks(str: string, toreplace: string, replacement: string): string { +/** + * replace string by other string + * @param input string, string to replace, replacement string + */ +export function replaceString( + str: string, + toreplace: string, + replacement: string +): string { // Find the index of the first occurrence of triple backticks - const index = str.indexOf(toreplace); + const index = str.indexOf(toreplace) if (index === -1) { - return str; // Return the original string if no triple backticks found + return str // Return the original string if no triple backticks found } // Replace the first occurrence of triple backticks with the replacement string - const replacedString = str.slice(0, index) + replacement + str.slice(index + toreplace.length); + const replacedString = + str.slice(0, index) + replacement + str.slice(index + toreplace.length) - return replacedString; + return replacedString } /** @@ -268,7 +385,6 @@ export async function handle(rcMessage: RcMessage): Promise { case 'ru': // User removed by case 'ul': // User left case 'ult': // User left team - /* case 'removed-user-from-team': // Removed user from team log.info( `Message ${rcMessage._id} is of type ${rcMessage.t}, removing member ${rcMessage.msg} from room ${room_id}` @@ -306,7 +422,6 @@ export async function handle(rcMessage: RcMessage): Promise { formatUserSessionOptions(userMapping.accessToken) ) return - */ case 'uj': // User joined channel case 'ujt': // User joined team case 'ut': // User joined conversation @@ -315,16 +430,16 @@ export async function handle(rcMessage: RcMessage): Promise { case 'added-user-to-team': // Added user to team case 'r': // Room name changed case 'rm': // Message removed - //log.warn( - // `Message ${rcMessage._id} is of type ${rcMessage.t}, for which Rocket.Chat does not provide the initial state information, skipping.` - //) + log.warn( + `Message ${rcMessage._id} is of type ${rcMessage.t}, for which Rocket.Chat does not provide the initial state information, skipping.` + ) return case 'user-muted': // User muted by default: - //log.warn( - // `Message ${rcMessage._id} is of unhandled type ${rcMessage.t}, skipping.` - //) + log.warn( + `Message ${rcMessage._id} is of unhandled type ${rcMessage.t}, skipping.` + ) return } } @@ -336,72 +451,67 @@ export async function handle(rcMessage: RcMessage): Promise { ) return } - const matrixMessage = mapMessage(rcMessage) - const ts = new Date(rcMessage.ts.$date).valueOf() - - if (rcMessage.tmid) { - const event_id = await getMessageId(rcMessage.tmid) - if (!event_id) { - log.warn(`Related message ${rcMessage.tmid} missing, skipping.`) - return - } else { - matrixMessage['m.relates_to'] = { - rel_type: 'm.thread', - event_id, - is_falling_back: true, - 'm.in_reply_to': { + if (rcMessage.msg) { + const matrixMessage = mapMessage(rcMessage) + + const ts = new Date(rcMessage.ts.$date).valueOf() + + if (rcMessage.tmid) { + const event_id = await getMessageId(rcMessage.tmid) + if (!event_id) { + log.warn(`Related message ${rcMessage.tmid} missing, skipping.`) + return + } else { + matrixMessage['m.relates_to'] = { + rel_type: 'm.thread', event_id, - }, - } - } - } - if (rcMessage.md) { - for (const item of rcMessage.md) { - let formatted_body: string = matrixMessage.body; - if (item.type === 'CODE') { - formatted_body = replaceFirstTripleBackticks(formatted_body, '```\n','
')
-        formatted_body = replaceFirstTripleBackticks(formatted_body, '\n```','
\n') - log.warn(matrixMessage.body) - log.warn(formatted_body) - matrixMessage.formatted_body = formatted_body - matrixMessage.format = `org.matrix.custom.html` - } else if (item.type === 'PARAGRAPH') { - for (const val of item.value) { - if (val.type === 'LINK') { - log.warn(`inside link`) - const regex: RegExp = /\[ \]\(https:\/[^?]+\?msg=([^)]+)\)/; - const replacedStr: string = matrixMessage.body.replace(regex, "aa"); - const match: RegExpExecArray | null = regex.exec(matrixMessage.body); - if (match && match[1]) { - const msgValue: string = match[1]; - log.warn(msgValue); // Output: "rwq7eGNCD7b4LqKaR" - } else { - log.warn("No match found"); - } - } + is_falling_back: true, + 'm.in_reply_to': { + event_id, + }, } } } - /* - const event_id = await getMessageId(rcMessage.tmid) - if (!event_id) { - log.warn(`Related message ${rcMessage.tmid} missing, skipping.`) - return - } else { - matrixMessage['m.relates_to'] = { - rel_type: 'm.thread', - event_id, - is_falling_back: true, - 'm.in_reply_to': { - event_id, - }, + let domain: string = getDomainName() + let formatted_body: string = matrixMessage.body + formatted_body = formatCodeBis(formatted_body, matrixMessage) + if (rcMessage.attachments) { + for (const attach of rcMessage.attachments) { + if (!attach.type) { + const regexMessageId: RegExp = /\[ \]\(https:\/[^?]+\?msg=([^)]+)\)/ + let messageMatrixId: string = '' + let authorMatrixId: string = '' + let message: string = '' + ;[formatted_body, messageMatrixId] = await formatLink(formatted_body) + ;[authorMatrixId, formatted_body, message] = await getFromAttachement( + formatted_body, + rcMessage.attachments, + matrixMessage + ) + const new_body: string = `> <${authorMatrixId}> ${message}` + const form_body: string = `
In reply to ${authorMatrixId}
${message}
` + const replacedStr: string = matrixMessage.body.replace( + regexMessageId, + new_body + ) + const replacedStrForm: string = formatted_body.replace( + regexMessageId, + form_body + ) + matrixMessage.body = replacedStr + formatted_body = replacedStrForm + matrixMessage.formatted_body = formatted_body + matrixMessage.format = `org.matrix.custom.html` + } } } - */ + await executeAndHandleMissingMember(() => + createEventsAndMapping(matrixMessage, room_id, user_id, ts, rcMessage) + ) + } else { + log.warn('no msg') + return } - await executeAndHandleMissingMember(() => - createEventsAndMapping(matrixMessage, room_id, user_id, ts, rcMessage) - ) } /** diff --git a/src/helpers/synapse.ts b/src/helpers/synapse.ts index c300aeb..42f5721 100644 --- a/src/helpers/synapse.ts +++ b/src/helpers/synapse.ts @@ -77,3 +77,23 @@ export async function getMatrixMembers( ).data.joined ) } + +/** + * Return domain name + * @param nothing + * @returns domain name + */ +export function getDomainName(): string { + let domain: string = ""; + const regexDomain: RegExp = /https:\/\/([^/]+)/; + if (process.env.SYNAPSE_URL) { + const matchh: RegExpExecArray | null = regexDomain.exec(process.env.SYNAPSE_URL); + if (matchh && matchh[1]) { + domain = matchh[1]; + log.warn(domain); + } else { + log.warn("No env SYNAPSE_URL provided"); + } + } + return domain +}