module Import end module Import::OTRS def self.request(part) url = Setting.get('import_otrs_endpoint') + '/' + part + ';Key=' + Setting.get('import_otrs_endpoint_key') puts 'GET: ' + url response = UserAgent.request( url, { :user => Setting.get('import_otrs_user'), :password => Setting.get('import_otrs_password'), }, ) if !response.success? puts "ERROR: #{response.error}" return end return response end def self.post(base, data) url = Setting.get('import_otrs_endpoint') + '/' + base data['Key'] = Setting.get('import_otrs_endpoint_key') puts 'POST: ' + url response = UserAgent.request( url, { :method => 'post', :data => data, :user => Setting.get('import_otrs_user'), :password => Setting.get('import_otrs_password'), }, ) if !response.success? puts "ERROR: #{response.error}" return end return response end def self.json(response) data = Encode.conv( 'utf8', response.body.to_s ) JSON.parse( data ) end def self.auth(username, password) response = post( "public.pl", { :Action => 'Export', :Type => 'Auth', :User => username, :Pw => password } ) return if !response return if !response.success? result = json(response) return result end def self.session(session_id) response = post( "public.pl", { :Action => 'Export', :Type => 'SessionCheck', :SessionID => session_id } ) return if !response return if !response.success? result = json(response) return result end def self.permission_sync(user, result, config) # check if required OTRS group exists types = { :required_group_ro => 'groups_ro', :required_group_rw => 'groups_rw', } types.each {|config_key,result_key| if config[config_key] return false if !result[result_key].has_value?( config[config_key] ) end } # sync roles / groups if config[:group_ro_role_map] || config[:group_rw_role_map] user.role_ids = [] user.save end types = { :group_ro_role_map => 'groups_ro', :group_rw_role_map => 'groups_rw', } types.each {|config_key,result_key| next if !config[config_key] config[config_key].each {|otrs_group, role| next if !result[result_key].has_value?( otrs_group ) role_ids = user.role_ids role = Role.where( :name => role ).first next if !role role_ids.push role.id user.role_ids = role_ids user.save } } if config[:always_role] config[:always_role].each {|role, active| next if !active role_ids = user.role_ids role = Role.where( :name => role ).first next if !role role_ids.push role.id user.role_ids = role_ids user.save } end end def self.start puts 'Start import...' # # set system in import mode # Setting.set('import_mode', true) # check if system is in import mode if !Setting.get('import_mode') raise "System is not in import mode!" end response = request("public.pl?Action=Export") return if !response return if !response.success? #self.ticket('156115') #return # create states state # create priorities priority # create groups ticket_group # create agents user # create customers # customer result = JSON.parse( response.body ) result = result.reverse Thread.abort_on_exception = true thread_count = 4 threads = {} (1..thread_count).each {|thread| threads[thread] = Thread.new { sleep thread * 3 puts "Started import thread# #{thread} ..." run = true while run ticket_ids = result.pop(20) if !ticket_ids.empty? self.ticket(ticket_ids) else puts "... thread# #{thread}, no more work." run = false end end } } (1..thread_count).each {|thread| threads[thread].join } return end def self.diff_worker return if !Setting.get('import_mode') return if Setting.get('import_otrs_endpoint') == 'http://otrs_host/otrs' self.diff end def self.diff puts 'Start diff...' # check if system is in import mode if !Setting.get('import_mode') raise "System is not in import mode!" end # create states state # create priorities priority # create groups ticket_group # create agents user self.ticket_diff() return end def self.ticket_diff() url = "public.pl?Action=Export;Type=TicketDiff;Limit=30" response = request( url ) return if !response return if !response.success? result = json(response) self._ticket_result(result) end def self.ticket(ticket_ids) url = "public.pl?Action=Export;Type=Ticket;" ticket_ids.each {|ticket_id| url = url + "TicketID=#{CGI::escape ticket_id};" } response = request( url ) return if !response return if !response.success? result = json(response) self._ticket_result(result) end def self._ticket_result(result) # puts result.inspect map = { :Ticket => { :Changed => :updated_at, :Created => :created_at, :CreateBy => :created_by_id, :TicketNumber => :number, :QueueID => :group_id, :StateID => :state_id, :PriorityID => :priority_id, :Owner => :owner, :CustomerUserID => :customer, :Title => :title, :TicketID => :id, :FirstResponse => :first_response, # :FirstResponseTimeDestinationDate => :first_response_escal_date, # :FirstResponseInMin => :first_response_in_min, # :FirstResponseDiffInMin => :first_response_diff_in_min, :Closed => :close_time, # :SoltutionTimeDestinationDate => :close_time_escal_date, # :CloseTimeInMin => :close_time_in_min, # :CloseTimeDiffInMin => :close_time_diff_in_min, }, :Article => { :SenderType => :sender, :ArticleType => :type, :TicketID => :ticket_id, :ArticleID => :id, :Body => :body, :From => :from, :To => :to, :Cc => :cc, :Subject => :subject, :InReplyTo => :in_reply_to, :MessageID => :message_id, # :ReplyTo => :reply_to, :References => :references, :Changed => :updated_at, :Created => :created_at, :ChangedBy => :updated_by_id, :CreatedBy => :created_by_id, }, } result.each {|record| # use transaction ActiveRecord::Base.transaction do ticket_new = { :title => '', :created_by_id => 1, :updated_by_id => 1, } map[:Ticket].each { |key,value| if record['Ticket'][key.to_s] && record['Ticket'][key.to_s].class == String ticket_new[value] = Encode.conv( 'utf8', record['Ticket'][key.to_s] ) else ticket_new[value] = record['Ticket'][key.to_s] end } # puts key.to_s # puts value.to_s #puts 'new ticket data ' + ticket_new.inspect # check if state already exists ticket_old = Ticket.where( :id => ticket_new[:id] ).first #puts 'TICKET OLD ' + ticket_old.inspect # find user if ticket_new[:owner] user = User.lookup( :login => ticket_new[:owner] ) if user ticket_new[:owner_id] = user.id else ticket_new[:owner_id] = 1 end ticket_new.delete(:owner) end if ticket_new[:customer] user = User.lookup( :login => ticket_new[:customer] ) if user ticket_new[:customer_id] = user.id else ticket_new[:customer_id] = 1 end ticket_new.delete(:customer) else ticket_new[:customer_id] = 1 end # puts 'ttt' + ticket_new.inspect # set state types if ticket_old puts "update Ticket.find(#{ticket_new[:id]})" ticket_old.update_attributes(ticket_new) else puts "add Ticket.find(#{ticket_new[:id]})" ticket = Ticket.new(ticket_new) ticket.id = ticket_new[:id] ticket.save end record['Articles'].each { |article| # get article values article_new = { :created_by_id => 1, :updated_by_id => 1, } map[:Article].each { |key,value| if article[key.to_s] article_new[value] = Encode.conv( 'utf8', article[key.to_s] ) end } # create customer/sender if needed if article_new[:sender] == 'customer' && article_new[:created_by_id].to_i == 1 && !article_new[:from].empty? # set extra headers begin email = Mail::Address.new( article_new[:from] ).address rescue email = article_new[:from] if article_new[:from] =~ /<(.+?)>/ email = $1 end end user = User.where( :email => email ).first if !user user = User.where( :login => email ).first end if !user begin display_name = Mail::Address.new( article_new[:from] ).display_name || ( Mail::Address.new( article_new[:from] ).comments && Mail::Address.new( article_new[:from] ).comments[0] ) rescue display_name = article_new[:from] end # do extra decoding because we needed to use field.value display_name = Mail::Field.new( 'X-From', display_name ).to_s roles = Role.lookup( :name => 'Customer' ) user = User.create( :login => email, :firstname => display_name, :lastname => '', :email => email, :password => '', :active => true, :role_ids => [roles.id], :updated_by_id => 1, :created_by_id => 1, ) end article_new[:created_by_id] = user.id end if article_new[:sender] == 'customer' article_new[:sender_id] = Ticket::Article::Sender.lookup( :name => 'Customer' ).id article_new.delete( :sender ) end if article_new[:sender] == 'agent' article_new[:sender_id] = Ticket::Article::Sender.lookup( :name => 'Agent' ).id article_new.delete( :sender ) end if article_new[:sender] == 'system' article_new[:sender_id] = Ticket::Article::Sender.lookup( :name => 'System' ).id article_new.delete( :sender ) end if article_new[:type] == 'email-external' article_new[:type_id] = Ticket::Article::Type.lookup( :name => 'email' ).id article_new[:internal] = false elsif article_new[:type] == 'email-internal' article_new[:type_id] = Ticket::Article::Type.lookup( :name => 'email' ).id article_new[:internal] = true elsif article_new[:type] == 'note-external' article_new[:type_id] = Ticket::Article::Type.lookup( :name => 'note' ).id article_new[:internal] = false elsif article_new[:type] == 'note-internal' article_new[:type_id] = Ticket::Article::Type.lookup( :name => 'note' ).id article_new[:internal] = true elsif article_new[:type] == 'phone' article_new[:type_id] = Ticket::Article::Type.lookup( :name => 'phone' ).id article_new[:internal] = false elsif article_new[:type] == 'webrequest' article_new[:type_id] = Ticket::Article::Type.lookup( :name => 'web' ).id article_new[:internal] = false else article_new[:type_id] = 9 end article_new.delete( :type ) article_old = Ticket::Article.where( :id => article_new[:id] ).first #puts 'ARTICLE OLD ' + article_old.inspect # set state types if article_old puts "update Ticket::Article.find(#{article_new[:id]})" # puts article_new.inspect article_old.update_attributes(article_new) else puts "add Ticket::Article.find(#{article_new[:id]})" article = Ticket::Article.new(article_new) article.id = article_new[:id] article.save end } record['History'].each { |history| # puts '-------' # puts history.inspect if history['HistoryType'] == 'NewTicket' History.add( :id => history['HistoryID'], :o_id => history['TicketID'], :history_type => 'created', :history_object => 'Ticket', :created_at => history['CreateTime'], :created_by_id => history['CreateBy'] ) end if history['HistoryType'] == 'StateUpdate' data = history['Name'] # "%%new%%open%%" from = nil to = nil if data =~ /%%(.+?)%%(.+?)%%/ from = $1 to = $2 state_from = Ticket::State.lookup( :name => from ) state_to = Ticket::State.lookup( :name => to ) if state_from from_id = state_from.id end if state_to to_id = state_to.id end end # puts "STATE UPDATE (#{history['HistoryID']}): -> #{from}->#{to}" History.add( :id => history['HistoryID'], :o_id => history['TicketID'], :history_type => 'updated', :history_object => 'Ticket', :history_attribute => 'state', :value_from => from, :id_from => from_id, :value_to => to, :id_to => to_id, :created_at => history['CreateTime'], :created_by_id => history['CreateBy'] ) end if history['HistoryType'] == 'Move' data = history['Name'] # "%%Queue1%%5%%Postmaster%%1" from = nil to = nil if data =~ /%%(.+?)%%(.+?)%%(.+?)%%(.+?)$/ from = $1 from_id = $2 to = $3 to_id = $4 end History.add( :id => history['HistoryID'], :o_id => history['TicketID'], :history_type => 'updated', :history_object => 'Ticket', :history_attribute => 'group', :value_from => from, :value_to => to, :id_from => from_id, :id_to => to_id, :created_at => history['CreateTime'], :created_by_id => history['CreateBy'] ) end if history['HistoryType'] == 'PriorityUpdate' data = history['Name'] # "%%3 normal%%3%%5 very high%%5" from = nil to = nil if data =~ /%%(.+?)%%(.+?)%%(.+?)%%(.+?)$/ from = $1 from_id = $2 to = $3 to_id = $4 end History.add( :id => history['HistoryID'], :o_id => history['TicketID'], :history_type => 'updated', :history_object => 'Ticket', :history_attribute => 'priority', :value_from => from, :value_to => to, :id_from => from_id, :id_to => to_id, :created_at => history['CreateTime'], :created_by_id => history['CreateBy'] ) end if history['ArticleID'] && history['ArticleID'] != 0 History.add( :id => history['HistoryID'], :o_id => history['ArticleID'], :history_type => 'created', :history_object => 'Ticket::Article', :related_o_id => history['TicketID'], :related_history_object => 'Ticket', :created_at => history['CreateTime'], :created_by_id => history['CreateBy'] ) end } end } end def self.state response = request( "public.pl?Action=Export;Type=State" ) return if !response return if !response.success? result = json(response) # puts result.inspect map = { :ChangeTime => :updated_at, :CreateTime => :created_at, :CreateBy => :created_by_id, :ChangeBy => :updated_by_id, :Name => :name, :ID => :id, :ValidID => :active, :Comment => :note, }; Ticket::State.all.each {|state| state.name = state.name + '_tmp' state.save } result.each { |state| _set_valid(state) # get new attributes state_new = { :created_by_id => 1, :updated_by_id => 1, } map.each { |key,value| if state[key.to_s] state_new[value] = state[key.to_s] end } # check if state already exists state_old = Ticket::State.where( :id => state_new[:id] ).first # puts 'st: ' + state['TypeName'] # set state types if state['TypeName'] == 'pending auto' state['TypeName'] = 'pending action' end state_type = Ticket::StateType.where( :name => state['TypeName'] ).first state_new[:state_type_id] = state_type.id if state_old # puts 'TS: ' + state_new.inspect state_old.update_attributes(state_new) else state = Ticket::State.new(state_new) state.id = state_new[:id] state.save end } end def self.priority response = request( "public.pl?Action=Export;Type=Priority" ) return if !response return if !response.success? result = json(response) map = { :ChangeTime => :updated_at, :CreateTime => :created_at, :CreateBy => :created_by_id, :ChangeBy => :updated_by_id, :Name => :name, :ID => :id, :ValidID => :active, :Comment => :note, }; result.each { |priority| _set_valid(priority) # get new attributes priority_new = { :created_by_id => 1, :updated_by_id => 1, } map.each { |key,value| if priority[key.to_s] priority_new[value] = priority[key.to_s] end } # check if state already exists priority_old = Ticket::Priority.where( :id => priority_new[:id] ).first # set state types if priority_old priority_old.update_attributes(priority_new) else priority = Ticket::Priority.new(priority_new) priority.id = priority_new[:id] priority.save end } end def self.ticket_group response = request( "public.pl?Action=Export;Type=Queue" ) return if !response return if !response.success? result = json(response) map = { :ChangeTime => :updated_at, :CreateTime => :created_at, :CreateBy => :created_by_id, :ChangeBy => :updated_by_id, :Name => :name, :QueueID => :id, :ValidID => :active, :Comment => :note, }; result.each { |group| _set_valid(group) # get new attributes group_new = { :created_by_id => 1, :updated_by_id => 1, } map.each { |key,value| if group[key.to_s] group_new[value] = group[key.to_s] end } # check if state already exists group_old = Group.where( :id => group_new[:id] ).first # set state types if group_old group_old.update_attributes(group_new) else group = Group.new(group_new) group.id = group_new[:id] group.save end } end def self.user response = request( "public.pl?Action=Export;Type=User" ) return if !response return if !response.success? result = json(response) map = { :ChangeTime => :updated_at, :CreateTime => :created_at, :CreateBy => :created_by_id, :ChangeBy => :updated_by_id, :UserID => :id, :ValidID => :active, :Comment => :note, :UserEmail => :email, :UserFirstname => :firstname, :UserLastname => :lastname, # :UserTitle => :UserLogin => :login, :UserPw => :password, }; result.each { |user| # puts 'USER: ' + user.inspect _set_valid(user) role = Role.lookup( :name => 'Agent' ) # get new attributes user_new = { :created_by_id => 1, :updated_by_id => 1, :source => 'OTRS Import', :role_ids => [ role.id ], } map.each { |key,value| if user[key.to_s] user_new[value] = user[key.to_s] end } # check if state already exists # user_old = User.where( :login => user_new[:login] ).first user_old = User.where( :id => user_new[:id] ).first # set state types if user_old puts "update User.find(#{user_new[:id]})" # puts 'Update User' + user_new.inspect user_new.delete( :role_ids ) user_old.update_attributes(user_new) else puts "add User.find(#{user_new[:id]})" # puts 'Add User' + user_new.inspect user = User.new(user_new) user.id = user_new[:id] user.save end # end } end def self.customer done = false count = 0 while done == false sleep 2 puts "Count=#{count};Offset=#{count}" response = request( "public.pl?Action=Export;Type=Customer;Count=100;Offset=#{count}" ) return if !response count = count + 3000 return if !response.success? result = json(response) map = { :ChangeTime => :updated_at, :CreateTime => :created_at, :CreateBy => :created_by_id, :ChangeBy => :updated_by_id, :ValidID => :active, :UserComment => :note, :UserEmail => :email, :UserFirstname => :firstname, :UserLastname => :lastname, # :UserTitle => :UserLogin => :login, :UserPassword => :password, :UserPhone => :phone, :UserFax => :fax, :UserMobile => :mobile, :UserStreet => :street, :UserZip => :zip, :UserCity => :city, :UserCountry => :country, }; done = true result.each { |user| done = false _set_valid(user) role = Role.lookup( :name => 'Customer' ) # get new attributes user_new = { :created_by_id => 1, :updated_by_id => 1, :source => 'OTRS Import', :role_ids => [role.id], } map.each { |key,value| if user[key.to_s] user_new[value] = user[key.to_s] end } # check if state already exists # user_old = User.where( :login => user_new[:login] ).first user_old = User.where( :login => user_new[:login] ).first # set state types if user_old puts "update User.find(#{user_new[:id]})" # puts 'Update User' + user_new.inspect user_old.update_attributes(user_new) else # puts 'Add User' + user_new.inspect puts "add User.find(#{user_new[:id]})" user = User.new(user_new) user.save end } end end def self._set_valid(record) # map if record['ValidID'] == '3' record['ValidID'] = '2' end if record['ValidID'] == '2' record['ValidID'] = false end if record['ValidID'] == '1' record['ValidID'] = true end if record['ValidID'] == '0' record['ValidID'] = false end end end