forward.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { getAttachmentLinks } from '#shared/composables/getAttachmentLinks.ts'
  3. import type {
  4. TicketArticle,
  5. TicketById,
  6. } from '#shared/entities/ticket/types.ts'
  7. import { useTicketArticleEmailForwardReplyMutation } from '#shared/entities/ticket-article/graphql/mutations/ticketArticleEmailForwardReply.api.ts'
  8. import type { TicketArticleEmailForwardReplyMutation } from '#shared/graphql/types.ts'
  9. import { i18n } from '#shared/i18n.ts'
  10. import { MutationHandler } from '#shared/server/apollo/handler/index.ts'
  11. import type { ConfigList } from '#shared/types/store.ts'
  12. import type { ConfidentTake } from '#shared/types/utils.ts'
  13. import { textCleanup, textToHtml } from '#shared/utils/helpers.ts'
  14. import type { TicketArticlePerformOptions } from '../types.ts'
  15. const forwardMutation = new MutationHandler(
  16. useTicketArticleEmailForwardReplyMutation({}),
  17. { errorShowNotification: true },
  18. )
  19. export const buildEmailForwardHeader = (
  20. article: TicketArticle,
  21. meta: ConfidentTake<
  22. TicketArticleEmailForwardReplyMutation,
  23. 'ticketArticleEmailForwardReply'
  24. >,
  25. ) => {
  26. const { quotableFrom, quotableCc, quotableTo } = meta || {}
  27. const fields = [
  28. [__('Subject'), article.subject],
  29. [__('Date'), i18n.dateTime(article.createdAt)],
  30. [__('From'), quotableFrom],
  31. [__('To'), quotableTo],
  32. [__('CC'), quotableCc],
  33. ] as const
  34. const output = fields.reduce((acc, [key, value]) => {
  35. if (value) {
  36. acc.append(i18n.t(key), ': ', value, document.createElement('br'))
  37. }
  38. return acc
  39. }, document.createElement('p'))
  40. output.appendChild(document.createElement('br'))
  41. return output.outerHTML
  42. }
  43. export const forwardEmail = async (
  44. ticket: TicketById,
  45. article: TicketArticle,
  46. options: TicketArticlePerformOptions,
  47. config: ConfigList,
  48. ) => {
  49. let body =
  50. article.contentType === 'text/html'
  51. ? textCleanup(article.bodyWithUrls)
  52. : textToHtml(textCleanup(article.bodyWithUrls))
  53. // TODO: standardise this in https://github.com/zammad/coordination-feature-mobile-view/issues/396
  54. body = body.replace(/<p><br><\/p>/g, '<p></p>') // cleanup
  55. const result = await forwardMutation
  56. .send({
  57. formId: options.formId,
  58. articleId: article.id,
  59. })
  60. .then((r) => r?.ticketArticleEmailForwardReply)
  61. // show attachment previews, but don't save its content
  62. const attachments = (result?.attachments || []).map((file, idx) => {
  63. const originalAttachment = article.attachmentsWithoutInline[idx]
  64. if (!originalAttachment || originalAttachment.name !== file.name)
  65. return file
  66. const { previewUrl, inlineUrl } = getAttachmentLinks(
  67. {
  68. internalId: originalAttachment.internalId,
  69. type: file.type,
  70. },
  71. config.api_path,
  72. )
  73. return {
  74. ...file,
  75. preview: previewUrl,
  76. inline: inlineUrl,
  77. }
  78. })
  79. const quotedHeader =
  80. config.ui_ticket_zoom_article_email_full_quote_header && result
  81. ? buildEmailForwardHeader(article, result)
  82. : ''
  83. const quotedBody = `<p data-marker="signature-before"></p><p>---${i18n.t(
  84. 'Begin forwarded message',
  85. )}:---</p><p></p><blockquote type="cite">${quotedHeader}${body}</blockquote>`
  86. return options.openReplyForm({
  87. articleType: 'email',
  88. subject: config.ui_ticket_zoom_article_email_subject
  89. ? article.subject || ticket.title
  90. : '',
  91. subtype: 'forward',
  92. attachments,
  93. body: quotedBody,
  94. })
  95. }