has_attachments.rb 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. module ApplicationModel::HasAttachments
  3. extend ActiveSupport::Concern
  4. included do
  5. after_create :attachments_buffer_check
  6. after_update :attachments_buffer_check
  7. after_destroy :attachments_remove_all, if: :attachments_cleanup?
  8. class_attribute :attachments_cleanup, default: false
  9. end
  10. class_methods do
  11. =begin
  12. mark model for cleaning up after destroying
  13. =end
  14. def attachments_cleanup!
  15. self.attachments_cleanup = true
  16. end
  17. end
  18. def attachments_remove_all
  19. attachments.each { |attachment| Store.remove_item(attachment.id) }
  20. end
  21. =begin
  22. get list of attachments of this object
  23. item = Model.find(123)
  24. list = item.attachments
  25. returns
  26. # array with Store model objects
  27. =end
  28. def attachments
  29. Store.list(object: self.class.to_s, o_id: id)
  30. end
  31. =begin
  32. store attachments for this object with store objects or hashes
  33. item = Model.find(123)
  34. item.attachments = [
  35. Store-Object1,
  36. Store-Object2,
  37. {
  38. filename: 'test.txt',
  39. data: 'test',
  40. preferences: {},
  41. }
  42. ]
  43. =end
  44. def attachments=(attachments)
  45. self.attachments_buffer = attachments
  46. # update if object already exists
  47. return if !id&.nonzero?
  48. attachments_buffer_check
  49. end
  50. =begin
  51. Returns attachments in ElasticSearch-compatible format
  52. For use in #search_index_attribute_lookup
  53. =end
  54. def attachments_for_search_index_attribute_lookup
  55. # list ignored file extensions
  56. attachments_ignore = Setting.get('es_attachment_ignore') || [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe' ]
  57. # max attachment size
  58. attachment_max_size_in_mb = (Setting.get('es_attachment_max_size_in_mb') || 10).megabytes
  59. attachment_total_max_size_in_kb = 314_572.kilobytes
  60. attachment_total_max_size_in_kb_current = 0.kilobytes
  61. attachments.each_with_object([]) do |attachment, memo|
  62. # check if attachment exists
  63. next if !attachment.content
  64. size_in_bytes = attachment.content.size.bytes
  65. # check file size
  66. next if size_in_bytes > attachment_max_size_in_mb
  67. # check ignored files
  68. next if !attachment.filename || attachments_ignore.include?(File.extname(attachment.filename).downcase)
  69. # check if fits into total size limit
  70. next if attachment_total_max_size_in_kb_current + size_in_bytes > attachment_total_max_size_in_kb
  71. attachment_total_max_size_in_kb_current += size_in_bytes
  72. memo << {
  73. '_name' => attachment.filename,
  74. '_content' => Base64.encode64(attachment.content).delete("\n")
  75. }
  76. end
  77. end
  78. private
  79. def attachments_buffer
  80. @attachments_buffer_data
  81. end
  82. def attachments_buffer=(attachments)
  83. @attachments_buffer_data = attachments
  84. end
  85. def attachments_buffer_check
  86. # do nothing if no attachment exists
  87. return 1 if attachments_buffer.nil?
  88. # store attachments
  89. article_store = []
  90. attachments_buffer.each do |attachment|
  91. data = {
  92. object: self.class.to_s,
  93. o_id: id,
  94. created_by_id: created_by_id,
  95. }
  96. if attachment.is_a?(Store)
  97. data[:data] = attachment.content
  98. data[:filename] = attachment.filename
  99. data[:preferences] = attachment.preferences
  100. else
  101. data[:data] = attachment[:data]
  102. data[:filename] = attachment[:filename]
  103. data[:preferences] = attachment[:preferences]
  104. end
  105. article_store.push Store.create!(data)
  106. end
  107. end
  108. end