class OTRS # This class is mostly used for inheritance purposes # All subclasses will be able to directly connect to OTRS # All subclasses have active_record style callbacks # Include stuff for calbacks, validations include ActiveModel::Conversion include ActiveModel::Naming include ActiveModel::Validations extend ActiveModel::Callbacks # Create callbacks on before/after create/save/update define_model_callbacks :create, :update, :save # api_url is the base URL used to connect to the json api of OTRS, this will be the custom json.pl as the standard doesn't include ITSM module @@otrs_api_url ||= "https://loalhost/otrs/json.pl" # Username / password combo should be an actual OTRS agent defined on the OTRS server @@otrs_user ||= 'rails' @@otrs_pass ||= 'rails' def self.user @@otrs_user end def self.user=(username) @@otrs_user = username end def self.password @@otrs_pass end def self.password=(password) @@otrs_pass = password end def self.api_url @@otrs_api_url end def self.api_url=(url) @@otrs_api_url = url end # Convert object's instance variables to a hash def attributes attributes = {} self.instance_variables.each do |v| attributes[v.to_s.gsub('@','').to_sym] = self.instance_variable_get(v) end attributes end # Handles communication with OTRS def self.setup_connection_params(params) if self.api_url =~ /^https/ require 'net/https' else require 'net/http' end base_url = self.api_url # Build request URL logon = URI.encode("User=#{self.user}&Password=#{self.password}") object = URI.encode(params[:object]) method = URI.encode(params[:method]) data = params[:data].to_json data = URI.encode(data) # Had some issues with certain characters not being escaped properly and causing JSON issues data = URI.escape(data, '=\',\\/+-&?#.;') URI.parse("#{base_url}?#{logon}&Object=#{object}&Method=#{method}&Data=#{data}") end def self.get_from_remote(uri, read_timeout=60) http = Net::HTTP.new(uri.host, uri.port) http.read_timeout = read_timeout if self.api_url =~ /^https/ http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE end request = Net::HTTP::Get.new(uri.request_uri) response = http.request(request) end def self.process_response(response) result = ActiveSupport::JSON::decode(response.body) if result["Result"] == 'successful' return result["Data"] else raise "Error:#{result["Result"]} #{result["Data"]}" end end def self.connect(params, timeout=60, retries=4) uri = self.setup_connection_params(params) retry_counter = 0 # Connect to OTRS begin response = self.get_from_remote(uri, timeout) rescue EOFError retry_counter += 1 puts "EOFError, Attempt: #{retry_counter+1}" retry if retry_counter < retries raise EOFError if retry_counter >= retries rescue Timeout::Error retry_counter += 1 timeout = timeout*1.5 puts "Timeout::Error Attempt: #{retry_counter+1}, Timeout #{timeout}" retry if retry_counter < retries raise Timeout::Error if retry_counter >= retries end return self.process_response(response) end # Base method for processing objects returned by OTRS into Ruby objects # This works in most cases, but not all, namely with OTRS::ConfigItem due to extra attributes def self.object_preprocessor(object) unless object.empty? or object.nil? a = Hash[*object] self.new(a.symbolize_keys) else raise 'NoSuchObject' end end # Not sure why this is here def connect(params) self.class.connect(params) end end