create.rb 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. class Service::Ticket::Article::Create < Service::BaseWithCurrentUser
  3. def execute(article_data:)
  4. ticket_id = article_data.delete(:ticket_id)
  5. if Ticket.find(ticket_id).nil?
  6. raise ActiveRecord::RecordNotFound, "Ticket #{ticket_id} for new article could not be found."
  7. end
  8. create_article(article_data, ticket_id)
  9. end
  10. private
  11. def create_article(article_data, ticket_id)
  12. attachments_raw = article_data.delete(:attachments) || {}
  13. form_id = attachments_raw[:form_id]
  14. preprocess_article_data(article_data)
  15. Ticket::Article.new(article_data).tap do |article|
  16. transform_article(article, ticket_id, attachments_raw)
  17. article.save!
  18. if article_data[:time_unit].present?
  19. time_accounting(article, article_data[:time_unit])
  20. end
  21. form_id_cleanup(form_id) if form_id.present?
  22. end
  23. end
  24. def preprocess_article_data(article_data)
  25. # Coerce recipient lists.
  26. %i[to cc].each do |field|
  27. if article_data[field].is_a? Array
  28. article_data[field] = article_data[field].join(', ')
  29. end
  30. end
  31. end
  32. def transform_article(article, ticket_id, attachments_raw)
  33. article.ticket_id = ticket_id
  34. article.attachments = attachments(article, attachments_raw)
  35. transform_to_from(article)
  36. article
  37. end
  38. def transform_to_from(article)
  39. ticket = Ticket.find(article.ticket_id)
  40. customer_display_name = display_name(ticket.customer)
  41. group_name = ticket.group.name
  42. if article.sender.name.eql?('Customer')
  43. article.from = customer_display_name
  44. article.to = group_name
  45. else
  46. article.to ||= customer_display_name
  47. article.from = group_name
  48. end
  49. end
  50. def display_name(user)
  51. if user.fullname.present? && user.email.present?
  52. return Mail::Address.new.tap do |addr|
  53. addr.display_name = user.fullname
  54. addr.address = user.email
  55. end.format
  56. end
  57. return user.fullname if user.fullname.present?
  58. display_name_fallback(user)
  59. end
  60. def display_name_fallback(user)
  61. return user.email if user.email.present?
  62. return user.phone if user.phone.present?
  63. return user.login if user.login.present?
  64. '-'
  65. end
  66. def attachments(article, attachments_raw)
  67. inline_attachments = []
  68. if article.body && article.content_type&.match?(%r{text/html}i)
  69. (article.body, inline_attachments) = HtmlSanitizer.replace_inline_images(article.body, article.ticket_id)
  70. end
  71. form_id = attachments_raw[:form_id]
  72. attachments = form_id ? UploadCache.new(form_id).attachments : []
  73. # Limit attachments to the ones that were really sent.
  74. attachments = limit_attachments(attachments, attachments_raw[:files])
  75. # Do not forget inline attachments.
  76. inline_attachments_map(inline_attachments, attachments)
  77. attachments
  78. end
  79. def inline_attachments_map(inline_attachments, attachments)
  80. inline_attachments.each do |attachment_inline|
  81. attachments.push({
  82. data: attachment_inline[:data],
  83. filename: attachment_inline[:filename],
  84. preferences: attachment_inline[:preferences],
  85. })
  86. end
  87. end
  88. def limit_attachments(attachments, file_meta)
  89. return attachments if file_meta.blank?
  90. attachments.reject { |attachment| file_meta.none? { |file| check_attachment_match(attachment, file) } }
  91. end
  92. def check_attachment_match(attachment, file)
  93. if file[:type].present? && attachment[:preferences].present? && attachment[:preferences]['Content-Type'].present?
  94. file[:name] == attachment[:filename] && file[:type] == attachment[:preferences]['Content-Type']
  95. end
  96. file[:name] == attachment[:filename]
  97. end
  98. def time_accounting(article, time_unit)
  99. Ticket::TimeAccounting.create!(
  100. ticket_id: article.ticket_id,
  101. ticket_article_id: article.id,
  102. time_unit: time_unit,
  103. )
  104. end
  105. def form_id_cleanup(form_id)
  106. # clear in-progress state from taskbar
  107. Taskbar
  108. .where(user_id: current_user.id)
  109. .first { |taskbar| taskbar.persisted_form_id == form_id }&.update!(state: {})
  110. # remove temporary attachment cache
  111. UploadCache.new(form_id).destroy
  112. end
  113. end