has_attachments.rb 2.9 KB

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