diff --git a/.changeset/weak-taxis-design.md b/.changeset/weak-taxis-design.md new file mode 100644 index 000000000000..a2d435495cd7 --- /dev/null +++ b/.changeset/weak-taxis-design.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': minor +--- + +Added handling of attachments in Omnichannel email transcripts. Earlier attachments were being skipped and were being shown as empty space, now it should render the image attachments and should show relevant error message for unsupported attachments. diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts index bb56eb81ceb3..800e32d85ab4 100644 --- a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -23,7 +23,8 @@ import type { LivechatDepartmentDTO, OmnichannelSourceType, } from '@rocket.chat/core-typings'; -import { ILivechatAgentStatus, UserStatus, isOmnichannelRoom } from '@rocket.chat/core-typings'; +import { ILivechatAgentStatus, UserStatus, isFileAttachment, isFileImageAttachment, isOmnichannelRoom } from '@rocket.chat/core-typings'; +import colors from '@rocket.chat/fuselage-tokens/colors.json'; import { Logger, type MainLogger } from '@rocket.chat/logger'; import { LivechatDepartment, @@ -37,6 +38,7 @@ import { ReadReceipts, Rooms, LivechatCustomField, + Uploads, } from '@rocket.chat/models'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; import { Match, check } from 'meteor/check'; @@ -613,6 +615,7 @@ class LivechatClass { 'livechat-started', 'livechat_video_call', ]; + const acceptableImageMimeTypes = ['image/jpeg', 'image/png', 'image/jpg']; const messages = await Messages.findVisibleByRoomIdNotContainingTypesBeforeTs( rid, ignoredMessageTypes, @@ -623,7 +626,14 @@ class LivechatClass { ); let html = '

'; - await messages.forEach((message) => { + const InvalidFileMessage = `
${i18n.t( + 'This_attachment_is_not_supported', + { lng: userLanguage }, + )}
`; + + for await (const message of messages) { let author; if (message.u._id === visitor._id) { author = i18n.t('You', { lng: userLanguage }); @@ -631,13 +641,60 @@ class LivechatClass { author = showAgentInfo ? message.u.name || message.u.username : i18n.t('Agent', { lng: userLanguage }); } + let messageContent = message.msg; + let filesHTML = ''; + + if (message.attachments && message.attachments?.length > 0) { + messageContent = message.attachments[0].description || ''; + + for await (const attachment of message.attachments) { + if (!isFileAttachment(attachment)) { + // ignore other types of attachments + continue; + } + + if (!isFileImageAttachment(attachment)) { + filesHTML += `
${attachment.title || ''}${InvalidFileMessage}
`; + continue; + } + + if (!attachment.image_type || !acceptableImageMimeTypes.includes(attachment.image_type)) { + filesHTML += `
${attachment.title || ''}${InvalidFileMessage}
`; + continue; + } + + // Image attachment can be rendered in email body + const file = message.files?.find((file) => file.name === attachment.title); + + if (!file) { + filesHTML += `
${attachment.title || ''}${InvalidFileMessage}
`; + continue; + } + + const uploadedFile = await Uploads.findOneById(file._id); + + if (!uploadedFile) { + filesHTML += `
${file.name}${InvalidFileMessage}
`; + continue; + } + + const uploadedFileBuffer = await FileUpload.getBuffer(uploadedFile); + filesHTML += `

${file.name}

`; + } + } + const datetime = moment.tz(message.ts, timezone).locale(userLanguage).format('LLL'); const singleMessage = `

${author} ${datetime}

-

${message.msg}

+

${messageContent}

+

${filesHTML}

`; html += singleMessage; - }); + } html = `${html}
`;