can_clone_attachments.rb 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. module CanCloneAttachments
  3. extend ActiveSupport::Concern
  4. =begin
  5. clone existing attachments of article to the target object
  6. article_parent = Ticket::Article.find(123)
  7. article_new = Ticket::Article.find(456)
  8. attached_attachments = article_parent.clone_attachments(article_new.class.name, article_new.id, only_attached_attachments: true)
  9. inline_attachments = article_parent.clone_attachments(article_new.class.name, article_new.id, only_inline_attachments: true)
  10. returns
  11. [attachment1, attachment2, ...]
  12. =end
  13. def clone_attachments(object_type, object_id, options = {})
  14. existing_attachments = Store.list(
  15. object: object_type,
  16. o_id: object_id,
  17. )
  18. is_html_content = content_type.present? && content_type =~ %r{text/html}i
  19. attachments
  20. .select do |elem|
  21. next if elem.preferences['content-alternative'] == true
  22. # only_attached_attachments mode is used by apply attached attachments to forwared article
  23. if options[:only_attached_attachments] == true && is_html_content
  24. content_id = elem.preferences['Content-ID'] || elem.preferences['content_id']
  25. next if content_id.present? && body.present? && body.match?(%r{#{Regexp.quote(content_id)}}i)
  26. end
  27. # only_inline_attachments mode is used when quoting HTML mail with #{article.body_as_html}
  28. if options[:only_inline_attachments] == true
  29. next if !is_html_content
  30. next if body.blank?
  31. content_disposition = elem.preferences['Content-Disposition'] || elem.preferences['content_disposition']
  32. next if content_disposition.present? && content_disposition.exclude?('inline')
  33. content_id = elem.preferences['Content-ID'] || elem.preferences['content_id']
  34. next if content_id.blank?
  35. next if !body.match?(%r{#{Regexp.quote(content_id)}}i)
  36. end
  37. next if existing_attachments.any? do |existing_attachment|
  38. existing_attachment.filename == elem.filename && existing_attachment.size == elem.size
  39. end
  40. true
  41. end
  42. .map do |elem|
  43. Store.create!(
  44. object: object_type,
  45. o_id: object_id,
  46. data: elem.content,
  47. filename: elem.filename,
  48. preferences: elem.preferences,
  49. )
  50. end
  51. end
  52. def attach_upload_cache(form_id, source_object_name: 'UploadCache')
  53. attachments
  54. .reject(&:inline?)
  55. .each { |attachment| Store.remove_item(attachment.id) }
  56. Store
  57. .list(object: source_object_name, o_id: form_id)
  58. .reject(&:inline?)
  59. .map do |old_attachment|
  60. Store.create!(
  61. object: self.class.name,
  62. o_id: id,
  63. data: old_attachment.content,
  64. filename: old_attachment.filename,
  65. preferences: old_attachment.preferences,
  66. )
  67. end
  68. end
  69. end