transaction.rb 5.8 KB

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