create.rb 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. class Service::Ticket::Article::Create < Service::BaseWithCurrentUser
  3. def execute(article_data:, ticket:)
  4. article_data.delete(:ticket_id)
  5. attachments_raw = article_data.delete(:attachments) || {}
  6. time_unit = article_data.delete(:time_unit)
  7. subtype = article_data.delete(:subtype)
  8. preprocess_article_data(article_data, ticket)
  9. ticket.articles.new(article_data).tap do |article|
  10. article.check_mentions_raises_error = true
  11. transform_article(article, attachments_raw, subtype)
  12. article.save!
  13. time_accounting(article, time_unit)
  14. form_id_cleanup(attachments_raw)
  15. end
  16. end
  17. private
  18. def preprocess_article_data(article_data, ticket)
  19. preprocess_type(article_data)
  20. preprocess_to_cc(article_data)
  21. preprocess_sender(article_data, ticket)
  22. preprocess_for_customer(article_data, ticket)
  23. end
  24. def preprocess_type(article_data)
  25. type_name = article_data[:type] || 'note'
  26. article_data[:type] = Ticket::Article::Type.lookup(name: type_name)
  27. end
  28. def preprocess_to_cc(article_data)
  29. %i[to cc].each do |field|
  30. article_data[field] = article_data[field].join(', ') if article_data[field].is_a? Array
  31. article_data[field] ||= ''
  32. end
  33. end
  34. def preprocess_sender(article_data, ticket)
  35. sender_name = if agent_on_ticket?(ticket)
  36. article_data[:sender].presence || 'Agent'
  37. else
  38. 'Customer'
  39. end
  40. article_data[:sender] = Ticket::Article::Sender.lookup(name: sender_name)
  41. end
  42. def preprocess_for_customer(article_data, ticket)
  43. return if agent_on_ticket?(ticket)
  44. if %w[note web].exclude? article_data[:type]&.name
  45. article_data[:type] = Ticket::Article::Type.lookup(name: 'note')
  46. end
  47. article_data.delete :origin_by_id
  48. article_data[:internal] = false
  49. end
  50. def transform_article(article, attachments_raw, subtype)
  51. transform_attachments(article, attachments_raw)
  52. # transform_to_from(article)
  53. transform_subtype(article, subtype)
  54. end
  55. def transform_subtype(article, subtype)
  56. article.preferences[:subtype] = subtype if subtype.present?
  57. end
  58. def transform_to_from(article)
  59. customer_display_name = display_name(article.ticket.customer)
  60. group_name = article.ticket.group.fullname
  61. if article.sender.name.eql?('Customer')
  62. article.from = customer_display_name
  63. article.to = group_name
  64. else
  65. article.to = customer_display_name if article.to.blank?
  66. article.from = group_name
  67. end
  68. end
  69. def transform_attachments(article, attachments_raw)
  70. inline_attachments = []
  71. if article.body && article.content_type&.include?('text/html')
  72. (article.body, inline_attachments) = HtmlSanitizer.replace_inline_images(article.body, article.ticket_id)
  73. end
  74. article.attachments = attached_attachments(attachments_raw) + inline_attachments_map(inline_attachments)
  75. end
  76. def inline_attachments_map(inline_attachments)
  77. inline_attachments.map do |elem|
  78. elem.slice(:data, :filename, :preferences)
  79. end
  80. end
  81. def attached_attachments(attachments_raw)
  82. form_id = attachments_raw[:form_id]
  83. file_meta = attachments_raw[:files]
  84. return [] if form_id.blank?
  85. UploadCache
  86. .new(form_id)
  87. .attachments
  88. .select do |elem|
  89. file_meta.any? { |file| check_attachment_match(elem, file) }
  90. end
  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. return if time_unit.blank?
  100. time_accounting = Ticket::TimeAccounting.new(
  101. ticket_id: article.ticket_id,
  102. ticket_article_id: article.id,
  103. time_unit: time_unit,
  104. )
  105. policy = Ticket::TimeAccountingPolicy.new(current_user, time_accounting)
  106. if !policy.create?
  107. raise policy.custom_exception || __('Not authorized')
  108. end
  109. time_accounting.save!
  110. end
  111. def form_id_cleanup(attachments_raw)
  112. form_id = attachments_raw[:form_id]
  113. return if form_id.blank?
  114. # clear in-progress state from taskbar
  115. Taskbar
  116. .where(user_id: current_user.id)
  117. .first { |taskbar| taskbar.persisted_form_id == form_id }&.update!(state: {})
  118. # remove temporary attachment cache
  119. UploadCache
  120. .new(form_id)
  121. .destroy
  122. end
  123. def agent_on_ticket?(_ticket)
  124. current_user.permissions?('ticket.agent')
  125. end
  126. def display_name(user)
  127. if user.fullname.present? && user.email.present?
  128. return Channel::EmailBuild.recipient_line user.fullname, user.email
  129. end
  130. return user.fullname if user.fullname.present?
  131. display_name_fallback(user)
  132. end
  133. def display_name_fallback(user)
  134. user.email.presence || user.phone.presence || user.login.presence || '-'
  135. end
  136. end