trigger_webhook_job.rb 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class TriggerWebhookJob < ApplicationJob
  3. attr_reader :ticket, :trigger, :article, :changes, :user_id, :execution_type, :event_type
  4. retry_on TriggerWebhookJob::RequestError, attempts: 5, wait: lambda { |executions|
  5. executions * 10.seconds
  6. }
  7. discard_on(ActiveJob::DeserializationError) do |_job, e|
  8. Rails.logger.info 'Trigger, Ticket or Article may got removed before TriggerWebhookJob could be executed. Discarding job. See exception for further details.'
  9. Rails.logger.info e
  10. end
  11. def perform(trigger, ticket, article, changes:, user_id:, execution_type:, event_type:)
  12. @trigger = trigger
  13. @ticket = ticket
  14. @article = article
  15. @changes = changes
  16. @user_id = user_id
  17. @execution_type = execution_type
  18. @event_type = event_type
  19. return if abort?
  20. return if request.success?
  21. raise TriggerWebhookJob::RequestError
  22. end
  23. private
  24. def abort?
  25. if webhook_id.blank?
  26. log_wrong_trigger_config
  27. return true
  28. elsif webhook.blank?
  29. log_not_existing_webhook
  30. return true
  31. end
  32. false
  33. end
  34. def webhook_id
  35. @webhook_id ||= trigger.perform.dig('notification.webhook', 'webhook_id')
  36. end
  37. def webhook
  38. @webhook ||= begin
  39. Webhook.find_by(
  40. id: webhook_id,
  41. active: true
  42. )
  43. end
  44. end
  45. def log_wrong_trigger_config
  46. Rails.logger.error "Can't find webhook_id for Trigger '#{trigger.name}' with ID #{trigger.id}"
  47. end
  48. def log_not_existing_webhook
  49. Rails.logger.error "Can't find Webhook for ID #{webhook_id} configured in Trigger '#{trigger.name}' with ID #{trigger.id}"
  50. end
  51. def request
  52. UserAgent.post(
  53. webhook.endpoint,
  54. payload,
  55. {
  56. json: true,
  57. jsonParseDisable: true,
  58. open_timeout: 4,
  59. read_timeout: 30,
  60. total_timeout: 60,
  61. headers: headers,
  62. signature_token: webhook.signature_token,
  63. verify_ssl: webhook.ssl_verify,
  64. user: webhook.basic_auth_username,
  65. password: webhook.basic_auth_password,
  66. log: {
  67. facility: 'webhook',
  68. },
  69. },
  70. )
  71. end
  72. def headers
  73. {
  74. 'X-Zammad-Trigger' => trigger.name,
  75. 'X-Zammad-Delivery' => job_id
  76. }
  77. end
  78. def default_payload
  79. {
  80. ticket: TriggerWebhookJob::RecordPayload.generate(ticket),
  81. article: TriggerWebhookJob::RecordPayload.generate(article),
  82. }
  83. end
  84. def payload
  85. return generate_custom_payload if webhook.customized_payload || webhook.pre_defined_webhook_type.present?
  86. default_payload
  87. end
  88. def pre_defined_webhook_payload
  89. TriggerWebhookJob::CustomPayload::Track::PreDefinedWebhook.payload(webhook.pre_defined_webhook_type)
  90. end
  91. def generate_custom_payload
  92. tracks = { ticket:, article: }
  93. add_custom_tracks(tracks)
  94. payload = webhook.customized_payload ? webhook.custom_payload : pre_defined_webhook_payload
  95. return default_payload if payload.nil?
  96. hash = TriggerWebhookJob::CustomPayload.generate(payload, tracks)
  97. return hash if webhook.customized_payload
  98. pre_defined_webhook = "Webhook::PreDefined::#{webhook.pre_defined_webhook_type}".constantize.new
  99. return hash if !pre_defined_webhook.respond_to?(:post_replace)
  100. pre_defined_webhook.post_replace(hash, tracks)
  101. end
  102. def add_custom_tracks(tracks)
  103. data = {
  104. event: {
  105. type: event_type,
  106. execution: execution_type,
  107. changes:,
  108. user_id:
  109. },
  110. webhook: webhook
  111. }
  112. TriggerWebhookJob::CustomPayload.tracks.each do |track|
  113. next if !track.respond_to?(:generate)
  114. track.generate(tracks, data)
  115. end
  116. end
  117. end