integration_base.rb 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. module Import
  3. # This base class handles regular integrations.
  4. # It provides generic interfaces for settings and active state.
  5. # It ensures that all requirements for a regular integration are met before a import can start.
  6. # It handles the case of an Scheduler interruption.
  7. #
  8. # It's required to implement the +start_import+ method which only has to start the import.
  9. class IntegrationBase < Import::Base
  10. def self.inherited(subclass)
  11. super
  12. subclass.extend(Forwardable)
  13. # delegate instance methods to the generic class implementations
  14. subclass.delegate %i[identifier active? config display_name] => subclass
  15. end
  16. # Defines the integration identifier used for
  17. # automatic config lookup and error message generation.
  18. #
  19. # @example
  20. # Import::Ldap.identifier
  21. # #=> "Ldap"
  22. #
  23. # return [String]
  24. def self.identifier
  25. name.split('::').last
  26. end
  27. # Provides the name that is used in texts visible to the user.
  28. #
  29. # @example
  30. # Import::Exchange.display_name
  31. # #=> "Exchange"
  32. #
  33. # return [String]
  34. def self.display_name
  35. identifier
  36. end
  37. # Checks if the integration is active.
  38. #
  39. # @example
  40. # Import::Ldap.active?
  41. # #=> true
  42. #
  43. # return [Boolean]
  44. def self.active?
  45. Setting.get("#{identifier.downcase}_integration") || false
  46. end
  47. # Provides the integration configuration.
  48. #
  49. # @example
  50. # Import::Ldap.config
  51. # #=> {"ssl_verify"=>true, "host_url"=>"ldaps://192...", ...}
  52. #
  53. # return [Hash] the configuration
  54. def self.config
  55. Setting.get("#{identifier.downcase}_config") || {}
  56. end
  57. # Stores the integration configuration.
  58. #
  59. # @example
  60. # Import::Ldap.config = {"ssl_verify"=>true, "host_url"=>"ldaps://192...", ...}
  61. #
  62. # return [nil]
  63. def self.config=(value)
  64. Setting.set("#{identifier.downcase}_config", value)
  65. end
  66. # Checks if the integration is activated and configured.
  67. # Otherwise it won't get queued since it will display
  68. # an error which is confusing and wrong.
  69. #
  70. # @example
  71. # Import::Ldap.queueable?
  72. # #=> true
  73. #
  74. # return [Boolean]
  75. def self.queueable?
  76. active? && config.present?
  77. end
  78. # Starts a live or dry run import.
  79. #
  80. # @example
  81. # instance = Import::Ldap.new(import_job)
  82. #
  83. # @raise [RuntimeError] Raised if an import should start but the integration is disabled
  84. #
  85. # return [nil]
  86. def start
  87. return if !requirements_completed?
  88. start_import
  89. end
  90. # Gets called when the Scheduler gets (re-)started and an ImportJob was still
  91. # in the queue. The job will always get restarted to avoid the gap till the next
  92. # run triggered by the Scheduler. The result will get updated to inform the user
  93. # in the agent interface result view.
  94. #
  95. # @example
  96. # instance = Import::Ldap.new(import_job)
  97. # instance.reschedule?(delayed_job)
  98. # #=> true
  99. #
  100. # return [true]
  101. def reschedule?(_delayed_job)
  102. inform('Restarting due to scheduler restart.')
  103. true
  104. end
  105. private
  106. def start_import
  107. raise "Missing implementation of method '#{__method__}' for #{self.class.name}"
  108. end
  109. def requirements_completed?
  110. return true if @import_job.dry_run
  111. if !active?
  112. message = "Sync cancelled. #{display_name} integration deactivated. Activate via the switch."
  113. elsif config.blank? && @import_job.payload.blank?
  114. message = "Sync cancelled. #{display_name} configration or ImportJob payload missing."
  115. end
  116. return true if !message
  117. inform(message)
  118. false
  119. end
  120. def inform(message)
  121. @import_job.update!(result: {
  122. info: message
  123. })
  124. end
  125. end
  126. end