transaction.rb 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. class Observer::Transaction < ActiveRecord::Observer
  3. observe :ticket, 'ticket::_article', :user, :organization, :tag
  4. def self.reset
  5. EventBuffer.reset('transaction')
  6. end
  7. def self.commit(params = {})
  8. # add attribute of interface handle (e. g. to send (no) notifications if a agent
  9. # is creating a ticket via application_server, but send it if it's created via
  10. # postmaster)
  11. params[:interface_handle] = ApplicationHandleInfo.current
  12. # execute object transactions
  13. Observer::Transaction.perform(params)
  14. end
  15. def self.perform(params)
  16. # return if we run import mode
  17. return if Setting.get('import_mode')
  18. # get buffer
  19. list = EventBuffer.list('transaction')
  20. # reset buffer
  21. EventBuffer.reset('transaction')
  22. # get asyn backends
  23. sync_backends = []
  24. Setting.where(area: 'Transaction::Backend::Sync').order(:name).each do |setting|
  25. backend = Setting.get(setting.name)
  26. next if params[:disable]&.include?(backend)
  27. sync_backends.push Kernel.const_get(backend)
  28. end
  29. # get uniq objects
  30. list_objects = get_uniq_changes(list)
  31. list_objects.each_value do |objects|
  32. objects.each_value do |item|
  33. # execute sync backends
  34. sync_backends.each do |backend|
  35. execute_singel_backend(backend, item, params)
  36. end
  37. # execute async backends
  38. Delayed::Job.enqueue(Transaction::BackgroundJob.new(item, params))
  39. end
  40. end
  41. end
  42. def self.execute_singel_backend(backend, item, params)
  43. Rails.logger.debug { "Execute singel backend #{backend}" }
  44. begin
  45. UserInfo.current_user_id = nil
  46. integration = backend.new(item, params)
  47. integration.perform
  48. rescue => e
  49. Rails.logger.error 'ERROR: ' + backend.inspect
  50. Rails.logger.error 'ERROR: ' + e.inspect
  51. Rails.logger.error e.backtrace.inspect
  52. end
  53. end
  54. =begin
  55. result = get_uniq_changes(events)
  56. result = {
  57. 'Ticket' =>
  58. 1 => {
  59. object: 'Ticket',
  60. type: 'create',
  61. object_id: 123,
  62. article_id: 123,
  63. user_id: 123,
  64. created_at: Time.zone.now,
  65. },
  66. 9 => {
  67. object: 'Ticket',
  68. type: 'update',
  69. object_id: 123,
  70. changes: {
  71. attribute1: [before, now],
  72. attribute2: [before, now],
  73. },
  74. user_id: 123,
  75. created_at: Time.zone.now,
  76. },
  77. },
  78. }
  79. result = {
  80. 'Ticket' =>
  81. 9 => {
  82. object: 'Ticket',
  83. type: 'update',
  84. object_id: 123,
  85. article_id: 123,
  86. changes: {
  87. attribute1: [before, now],
  88. attribute2: [before, now],
  89. },
  90. user_id: 123,
  91. created_at: Time.zone.now,
  92. },
  93. },
  94. }
  95. =end
  96. def self.get_uniq_changes(events)
  97. list_objects = {}
  98. events.each do |event|
  99. # simulate article create as ticket update
  100. article = nil
  101. if event[:object] == 'Ticket::Article'
  102. article = Ticket::Article.find_by(id: event[:id])
  103. next if !article
  104. next if event[:type] == 'update'
  105. # set new event infos
  106. ticket = Ticket.find_by(id: article.ticket_id)
  107. event[:object] = 'Ticket'
  108. event[:id] = ticket.id
  109. event[:type] = 'update'
  110. event[:changes] = nil
  111. end
  112. # get current state of objects
  113. object = Kernel.const_get(event[:object]).find_by(id: event[:id])
  114. # next if object is already deleted
  115. next if !object
  116. if !list_objects[event[:object]]
  117. list_objects[event[:object]] = {}
  118. end
  119. if !list_objects[event[:object]][object.id]
  120. list_objects[event[:object]][object.id] = {}
  121. end
  122. store = list_objects[event[:object]][object.id]
  123. store[:object] = event[:object]
  124. store[:object_id] = object.id
  125. store[:user_id] = event[:user_id]
  126. store[:created_at] = event[:created_at]
  127. if !store[:type] || store[:type] == 'update'
  128. store[:type] = event[:type]
  129. end
  130. # merge changes
  131. if event[:changes]
  132. if !store[:changes]
  133. store[:changes] = event[:changes]
  134. else
  135. event[:changes].each do |key, value|
  136. if !store[:changes][key]
  137. store[:changes][key] = value
  138. else
  139. store[:changes][key][1] = value[1]
  140. end
  141. end
  142. end
  143. end
  144. # remember article id if exists
  145. if article
  146. store[:article_id] = article.id
  147. end
  148. end
  149. list_objects
  150. end
  151. def after_create(record)
  152. # return if we run import mode
  153. return true if Setting.get('import_mode')
  154. e = {
  155. object: record.class.name,
  156. type: 'create',
  157. data: record,
  158. id: record.id,
  159. user_id: record.created_by_id,
  160. created_at: Time.zone.now,
  161. }
  162. EventBuffer.add('transaction', e)
  163. true
  164. end
  165. def before_update(record)
  166. # return if we run import mode
  167. return true if Setting.get('import_mode')
  168. # ignore certain attributes
  169. real_changes = {}
  170. record.changes_to_save.each do |key, value|
  171. next if key == 'updated_at'
  172. next if key == 'first_response_at'
  173. next if key == 'close_at'
  174. next if key == 'last_contact_agent_at'
  175. next if key == 'last_contact_customer_at'
  176. next if key == 'last_contact_at'
  177. next if key == 'article_count'
  178. next if key == 'create_article_type_id'
  179. next if key == 'create_article_sender_id'
  180. real_changes[key] = value
  181. end
  182. # do not send anything if nothing has changed
  183. return true if real_changes.blank?
  184. changed_by_id = nil
  185. changed_by_id = if record.respond_to?('updated_by_id')
  186. record.updated_by_id
  187. else
  188. record.created_by_id
  189. end
  190. e = {
  191. object: record.class.name,
  192. type: 'update',
  193. data: record,
  194. changes: real_changes,
  195. id: record.id,
  196. user_id: changed_by_id,
  197. created_at: Time.zone.now,
  198. }
  199. EventBuffer.add('transaction', e)
  200. true
  201. end
  202. end