zammad/lib/import/integration_base.rb
2026-01-02 15:41:09 +02:00

138 lines
3.5 KiB
Ruby

# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
module Import
# This base class handles regular integrations.
# It provides generic interfaces for settings and active state.
# It ensures that all requirements for a regular integration are met before a import can start.
# It handles the case of a background worker interruption.
#
# It's required to implement the +start_import+ method which only has to start the import.
class IntegrationBase < Import::Base
def self.inherited(subclass)
super
subclass.extend(Forwardable)
# delegate instance methods to the generic class implementations
subclass.delegate %i[identifier active? config display_name] => subclass
end
# Defines the integration identifier used for
# automatic config lookup and error message generation.
#
# @example
# Import::Ldap.identifier
# #=> "Ldap"
#
# return [String]
def self.identifier
name.split('::').last
end
# Provides the name that is used in texts visible to the user.
#
# @example
# Import::Exchange.display_name
# #=> "Exchange"
#
# return [String]
def self.display_name
identifier
end
# Checks if the integration is active.
#
# @example
# Import::Ldap.active?
# #=> true
#
# return [Boolean]
def self.active?
Setting.get("#{identifier.downcase}_integration") || false
end
# Provides the integration configuration.
#
# return [Hash] the configuration
def self.config
Setting.get("#{identifier.downcase}_config") || {}
end
# Stores the integration configuration.
#
# return [nil]
def self.config=(value)
Setting.set("#{identifier.downcase}_config", value)
end
# Checks if the integration is activated and configured.
# Otherwise it won't get queued since it will display
# an error which is confusing and wrong.
#
# @example
# Import::Exchange.queueable?
# #=> true
#
# return [Boolean]
def self.queueable?
active? && config.present?
end
# Starts a live or dry run import.
#
# @example
# instance = Import::Ldap.new(import_job)
#
# @raise [RuntimeError] Raised if an import should start but the integration is disabled
#
# return [nil]
def start
return if !requirements_completed?
start_import
end
# Gets called when the background worker gets (re-)started and an ImportJob was still
# in the queue. The job will always get restarted to avoid the gap till the next
# run triggered by the background worker. The result will get updated to inform the user
# in the agent interface result view.
#
# @example
# instance = Import::Ldap.new(import_job)
# instance.reschedule?(delayed_job)
# #=> true
#
# return [true]
def reschedule?(_delayed_job)
inform('Restarting due to scheduler restart.')
true
end
private
def start_import
raise "Missing implementation of method '#{__method__}' for #{self.class.name}"
end
def requirements_completed?
return true if @import_job.dry_run
if !active?
message = "Sync cancelled. #{display_name} integration deactivated. Activate via the switch."
end
return true if !message
inform(message)
false
end
def inform(message)
@import_job.update!(result: {
info: message
})
end
end
end