create.rb 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # Copyright (C) 2012-2024 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_subtype(article, subtype)
  53. end
  54. def transform_subtype(article, subtype)
  55. article.preferences[:subtype] = subtype if subtype.present?
  56. end
  57. def transform_attachments(article, attachments_raw)
  58. inline_attachments = []
  59. if article.body && article.content_type&.include?('text/html')
  60. (article.body, inline_attachments) = HtmlSanitizer.replace_inline_images(article.body, article.ticket_id)
  61. end
  62. article.attachments = attached_attachments(attachments_raw) + inline_attachments_map(inline_attachments)
  63. end
  64. def inline_attachments_map(inline_attachments)
  65. inline_attachments.map do |elem|
  66. elem.slice(:data, :filename, :preferences)
  67. end
  68. end
  69. def attached_attachments(attachments_raw)
  70. form_id = attachments_raw[:form_id]
  71. file_meta = attachments_raw[:files]
  72. return [] if form_id.blank?
  73. UploadCache
  74. .new(form_id)
  75. .attachments
  76. .select do |elem|
  77. file_meta.any? { |file| check_attachment_match(elem, file) }
  78. end
  79. end
  80. def check_attachment_match(attachment, file)
  81. if file[:type].present? && attachment[:preferences].present? && attachment[:preferences]['Content-Type'].present?
  82. file[:name] == attachment[:filename] && file[:type] == attachment[:preferences]['Content-Type']
  83. end
  84. file[:name] == attachment[:filename]
  85. end
  86. def time_accounting(article, time_unit)
  87. return if time_unit.blank?
  88. time_accounting = Ticket::TimeAccounting.new(
  89. ticket_id: article.ticket_id,
  90. ticket_article_id: article.id,
  91. time_unit: time_unit,
  92. )
  93. policy = Ticket::TimeAccountingPolicy.new(current_user, time_accounting)
  94. if !policy.create?
  95. raise policy.custom_exception || __('Not authorized')
  96. end
  97. time_accounting.save!
  98. end
  99. def form_id_cleanup(attachments_raw)
  100. form_id = attachments_raw[:form_id]
  101. return if form_id.blank?
  102. # clear in-progress state from taskbar
  103. Taskbar
  104. .where(user_id: current_user.id)
  105. .first { |taskbar| taskbar.persisted_form_id == form_id }&.update!(state: {})
  106. # remove temporary attachment cache
  107. UploadCache
  108. .new(form_id)
  109. .destroy
  110. end
  111. def agent_on_ticket?(_ticket)
  112. current_user.permissions?('ticket.agent')
  113. end
  114. def display_name(user)
  115. if user.fullname.present? && user.email.present?
  116. return Channel::EmailBuild.recipient_line user.fullname, user.email
  117. end
  118. return user.fullname if user.fullname.present?
  119. display_name_fallback(user)
  120. end
  121. def display_name_fallback(user)
  122. user.email.presence || user.phone.presence || user.mobile.presence || user.login.presence || '-'
  123. end
  124. end