12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463 |
- require 'base64'
- module Import
- end
- module Import::OTRS
- =begin
- result = request_json(Subaction: 'List', 1)
- return
- { some json structure }
- result = request_json(Subaction: 'List')
- return
- "some data string"
- =end
- def self.request_json(data, data_only = false)
- response = post(data)
- if !response
- raise "Can't connect to Zammad Migrator"
- end
- if !response.success?
- raise "Can't connect to Zammad Migrator"
- end
- result = json(response)
- if !result
- raise 'Invalid response'
- end
- if data_only
- result['Result']
- else
- result
- end
- end
- =begin
- start get request to backend, add auth data automatically
- result = request('Subaction=List')
- return
- "some data string"
- =end
- def self.request(part)
- url = Setting.get('import_otrs_endpoint') + part + ';Key=' + Setting.get('import_otrs_endpoint_key')
- log 'GET: ' + url
- response = UserAgent.get(
- url,
- {},
- {
- open_timeout: 10,
- read_timeout: 60,
- total_timeout: 180,
- user: Setting.get('import_otrs_user'),
- password: Setting.get('import_otrs_password'),
- },
- )
- if !response.success?
- log "ERROR: #{response.error}"
- return
- end
- response
- end
- =begin
- start post request to backend, add auth data automatically
- result = request('Subaction=List')
- return
- "some data string"
- =end
- def self.post(data, url = nil)
- if !url
- url = Setting.get('import_otrs_endpoint')
- data['Action'] = 'ZammadMigrator'
- end
- data['Key'] = Setting.get('import_otrs_endpoint_key')
- log 'POST: ' + url
- log 'PARAMS: ' + data.inspect
- open_timeout = 10
- read_timeout = 120
- total_timeout = 360
- if data.empty?
- open_timeout = 6
- read_timeout = 20
- total_timeout = 120
- end
- response = UserAgent.post(
- url,
- data,
- {
- open_timeout: open_timeout,
- read_timeout: read_timeout,
- total_timeout: total_timeout,
- user: Setting.get('import_otrs_user'),
- password: Setting.get('import_otrs_password'),
- },
- )
- if !response.success?
- log "ERROR: #{response.error}"
- return
- end
- response
- end
- =begin
- start post request to backend, add auth data automatically
- result = json('some response string')
- return
- {}
- =end
- def self.json(response)
- data = Encode.conv('utf8', response.body.to_s)
- JSON.parse(data)
- end
- =begin
- start auth on OTRS - just for experimental reasons
- result = auth(username, password)
- return
- { ..user structure.. }
- =end
- def self.auth(username, password)
- url = Setting.get('import_otrs_endpoint')
- url.gsub!('ZammadMigrator', 'ZammadSSO')
- response = post( { Action: 'ZammadSSO', Subaction: 'Auth', User: username, Pw: password }, url )
- return if !response
- return if !response.success?
- result = json(response)
- result
- end
- =begin
- request session data - just for experimental reasons
- result = session(session_id)
- return
- { ..session structure.. }
- =end
- def self.session(session_id)
- url = Setting.get('import_otrs_endpoint')
- url.gsub!('ZammadMigrator', 'ZammadSSO')
- response = post( { Action: 'ZammadSSO', Subaction: 'SessionCheck', SessionID: session_id }, url )
- return if !response
- return if !response.success?
- result = json(response)
- result
- end
- =begin
- load objects from otrs
- result = load('SysConfig')
- return
- [
- { ..object1.. },
- { ..object2.. },
- { ..object3.. },
- ]
- =end
- def self.load( object, limit = '', offset = '', diff = 0 )
- request_json( { Subaction: 'Export', Object: object, Limit: limit, Offset: offset, Diff: diff }, 1 )
- end
- =begin
- start get request to backend to check connection
- result = connection_test
- return
- true | false
- =end
- def self.connection_test
- request_json({})
- end
- =begin
- get object statistic from remote server ans save it in cache
- result = statistic('Subaction=List')
- return
- {
- 'Ticket' => 1234,
- 'User' => 123,
- 'SomeObject' => 999,
- }
- =end
- def self.statistic
- # check cache
- cache = Cache.get('import_otrs_stats')
- if cache
- return cache
- end
- # retrive statistic
- statistic = request_json( { Subaction: 'List' }, 1)
- if statistic
- Cache.write('import_otrs_stats', statistic)
- end
- statistic
- end
- =begin
- return current import state
- result = current_state
- return
- {
- Ticket: {
- total: 1234,
- done: 13,
- },
- Base: {
- total: 1234,
- done: 13,
- },
- }
- =end
- def self.current_state
- data = statistic
- base = Group.count + Ticket::State.count + Ticket::Priority.count
- base_total = data['Queue'] + data['State'] + data['Priority']
- user = User.count
- user_total = data['User'] + data['CustomerUser']
- data = {
- Base: {
- done: base,
- total: base_total || 0,
- },
- User: {
- done: user,
- total: user_total || 0,
- },
- Ticket: {
- done: Ticket.count,
- total: data['Ticket'] || 0,
- },
- }
- data
- end
- #
- # start import
- #
- # Import::OTRS.start
- #
- def self.start
- log 'Start import...'
- # check if system is in import mode
- if !Setting.get('import_mode')
- raise 'System is not in import mode!'
- end
- result = request_json({})
- if !result['Success']
- raise 'API key not valid!'
- end
- # set settings
- settings = load('SysConfig')
- setting(settings)
- # dynamic fields
- dynamic_fields = load('DynamicField')
- #settings(dynamic_fields, settings)
- # email accounts
- #accounts = load('PostMasterAccount')
- #account(accounts)
- # email filter
- #filters = load('PostMasterFilter')
- #filter(filters)
- # create states
- states = load('State')
- ActiveRecord::Base.transaction do
- state(states)
- end
- # create priorities
- priorities = load('Priority')
- ActiveRecord::Base.transaction do
- priority(priorities)
- end
- # create groups
- queues = load('Queue')
- ActiveRecord::Base.transaction do
- ticket_group(queues)
- end
- # get agents groups
- groups = load('Group')
- # get agents roles
- roles = load('Role')
- # create agents
- users = load('User')
- ActiveRecord::Base.transaction do
- user(users, groups, roles, queues)
- end
- # create organizations
- organizations = load('Customer')
- ActiveRecord::Base.transaction do
- organization(organizations)
- end
- # create customers
- count = 0
- steps = 50
- run = true
- while run
- count += steps
- records = load('CustomerUser', steps, count - steps)
- if !records || !records[0]
- log 'all customers imported.'
- run = false
- next
- end
- customer(records, organizations)
- end
- Thread.abort_on_exception = true
- thread_count = 8
- threads = {}
- steps = 20
- (1..thread_count).each { |thread|
- threads[thread] = Thread.new {
- log "Started import thread# #{thread} ..."
- Thread.current[:thread_no] = thread
- Thread.current[:loop_count] = 0
- loop do
- # get the offset for the current thread and loop count
- thread_offset_base = (Thread.current[:thread_no] - 1) * steps
- thread_step = thread_count * steps
- offset = Thread.current[:loop_count] * thread_step + thread_offset_base
- log "loading... thread# #{thread} ..."
- records = load( 'Ticket', steps, offset)
- if !records || !records[0]
- log "... thread# #{thread}, no more work."
- break
- end
- _ticket_result(records, thread)
- Thread.current[:loop_count] += 1
- end
- ActiveRecord::Base.connection.close
- }
- }
- (1..thread_count).each {|thread|
- threads[thread].join
- }
- true
- end
- =begin
- start import in background
- Import::OTRS.start_bg
- =end
- def self.start_bg
- Setting.reload
- Import::OTRS.connection_test
- # start thread to observe current state
- status_update_thread = Thread.new {
- loop do
- result = {
- data: current_state,
- result: 'in_progress',
- }
- Cache.write('import:state', result, expires_in: 10.minutes)
- sleep 8
- end
- }
- sleep 2
- # start import data
- begin
- Import::OTRS.start
- rescue => e
- status_update_thread.exit
- status_update_thread.join
- Rails.logger.error e.message
- Rails.logger.error e.backtrace.inspect
- result = {
- message: e.message,
- result: 'error',
- }
- Cache.write('import:state', result, expires_in: 10.hours)
- return false
- end
- sleep 16 # wait until new finished import state is on client
- status_update_thread.exit
- status_update_thread.join
- result = {
- result: 'import_done',
- }
- Cache.write('import:state', result, expires_in: 10.hours)
- Setting.set('system_init_done', true)
- Setting.set('import_mode', false)
- end
- =begin
- get import state from background process
- result = Import::OTRS.status_bg
- =end
- def self.status_bg
- state = Cache.get('import:state')
- return state if state
- {
- message: 'not running',
- }
- end
- def self.diff_worker
- return if !Setting.get('import_mode')
- return if Setting.get('import_otrs_endpoint') == 'http://otrs_host/otrs'
- diff
- end
- def self.diff
- log 'Start diff...'
- # check if system is in import mode
- if !Setting.get('import_mode')
- raise 'System is not in import mode!'
- end
- # create states
- states = load('State')
- state(states)
- # create priorities
- priorities = load('Priority')
- priority(priorities)
- # create groups
- queues = load('Queue')
- ticket_group(queues)
- # get agents groups
- groups = load('Group')
- # get agents roles
- roles = load('Role')
- # create agents
- users = load('User')
- user(users, groups, roles, queues)
- # create organizations
- organizations = load('Customer')
- organization(organizations)
- # get changed tickets
- ticket_diff
- end
- def self.ticket_diff
- count = 0
- run = true
- steps = 20
- while run
- count += steps
- log 'loading... diff ...'
- records = load( 'Ticket', steps, count - steps, 1 )
- if !records || !records[0]
- log '... no more work.'
- run = false
- next
- end
- _ticket_result(records)
- end
- end
- def self._ticket_result(result, _thread = '-')
- 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|
- # cleanup values
- _cleanup(record)
- _utf8_encode(record)
- ticket_new = {
- title: '',
- created_by_id: 1,
- updated_by_id: 1,
- }
- map[:Ticket].each { |key, value|
- next if !record.key?(key.to_s)
- ticket_new[value] = record[key.to_s]
- }
- # find owner
- if ticket_new[:owner]
- user = User.find_by(login: ticket_new[:owner].downcase)
- ticket_new[:owner_id] = if user
- user.id
- else
- 1
- end
- ticket_new.delete(:owner)
- end
- # find customer
- if ticket_new[:customer]
- user = User.lookup(login: ticket_new[:customer].downcase)
- ticket_new[:customer_id] = if user
- user.id
- else
- 1
- end
- ticket_new.delete(:customer)
- else
- ticket_new[:customer_id] = 1
- end
- # update or create ticket
- ticket_old = Ticket.find_by(id: ticket_new[:id])
- if ticket_old
- log "update Ticket.find(#{ticket_new[:id]})"
- ticket_old.update_attributes(ticket_new)
- else
- log "add Ticket.find(#{ticket_new[:id]})"
- begin
- ticket = Ticket.new(ticket_new)
- ticket.id = ticket_new[:id]
- ticket.save
- _reset_pk('tickets')
- rescue ActiveRecord::RecordNotUnique
- log "Ticket #{ticket_new[:id]} is handled by another thead, skipping."
- next
- end
- end
- # utf8 encode
- record['Articles'].each { |article|
- _utf8_encode(article)
- }
- # lookup customers to create first
- record['Articles'].each { |article|
- _article_based_customers(article)
- }
- record['Articles'].each do |article|
- retries = 3
- begin
- ActiveRecord::Base.transaction do
- # get article values
- article_new = {
- created_by_id: 1,
- updated_by_id: 1,
- }
- map[:Article].each { |key, value|
- next if !article.key?(key.to_s)
- article_new[value] = article[key.to_s]
- }
- 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_object = Ticket::Article.find_by(id: article_new[:id])
- # set state types
- if article_object
- log "update Ticket::Article.find(#{article_new[:id]})"
- article_object.update_attributes(article_new)
- else
- log "add Ticket::Article.find(#{article_new[:id]})"
- begin
- article_object = Ticket::Article.new(article_new)
- article_object.id = article_new[:id]
- article_object.save
- _reset_pk('ticket_articles')
- rescue ActiveRecord::RecordNotUnique
- log "Ticket #{ticket_new[:id]} (article #{article_new[:id]}) is handled by another thead, skipping."
- next
- end
- end
- next if !article['Attachments']
- next if article['Attachments'].empty?
- # TODO: refactor
- # check if there are attachments present
- if !article_object.attachments.empty?
- # skip attachments if count is equal
- next if article_object.attachments.count == article['Attachments'].count
- # if the count differs delete all so we
- # can have a fresh start
- article_object.attachments.each(&:delete)
- end
- # import article attachments
- article['Attachments'].each { |attachment|
- filename = Base64.decode64(attachment['Filename'])
- Store.add(
- object: 'Ticket::Article',
- o_id: article_object.id,
- filename: filename,
- data: Base64.decode64(attachment['Content']),
- preferences: {
- 'Mime-Type' => attachment['ContentType'],
- 'Content-ID' => attachment['ContentID'],
- 'content-alternative' => attachment['ContentAlternative'],
- },
- created_by_id: 1,
- )
- }
- end
- rescue ActiveRecord::RecordNotUnique => e
- log "Ticket #{ticket_new[:id]} - RecordNotUnique: #{e}"
- sleep rand 3
- retry if !(retries -= 1).zero?
- raise
- end
- end
- #puts "HS: #{record['History'].inspect}"
- record['History'].each { |history|
- begin
- 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']
- )
- elsif 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
- 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']
- )
- elsif 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']
- )
- elsif 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']
- )
- elsif history['ArticleID'] && !history['ArticleID'].to_i.zero?
- 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
- rescue ActiveRecord::RecordNotUnique
- log "Ticket #{ticket_new[:id]} (history #{history['HistoryID']}) is handled by another thead, skipping."
- next
- end
- }
- }
- end
- # sync ticket states
- def self.state(records)
- map = {
- ChangeTime: :updated_at,
- CreateTime: :created_at,
- CreateBy: :created_by_id,
- ChangeBy: :updated_by_id,
- Name: :name,
- ID: :id,
- ValidID: :active,
- Comment: :note,
- }
- # rename states to handle not uniq issues
- Ticket::State.all.each {|state|
- state.name = state.name + '_tmp'
- state.save
- }
- records.each { |state|
- _set_valid(state)
- # get new attributes
- state_new = {
- created_by_id: 1,
- updated_by_id: 1,
- }
- map.each { |key, value|
- next if !state.key?(key.to_s)
- state_new[value] = state[key.to_s]
- }
- # check if state already exists
- state_old = Ticket::State.lookup(id: state_new[:id])
- # set state types
- if state['TypeName'] == 'pending auto'
- state['TypeName'] = 'pending action'
- end
- state_type = Ticket::StateType.lookup(name: state['TypeName'])
- state_new[:state_type_id] = state_type.id
- if state_old
- state_old.update_attributes(state_new)
- else
- state = Ticket::State.new(state_new)
- state.id = state_new[:id]
- state.save
- _reset_pk('ticket_states')
- end
- }
- end
- # sync ticket priorities
- def self.priority(records)
- map = {
- ChangeTime: :updated_at,
- CreateTime: :created_at,
- CreateBy: :created_by_id,
- ChangeBy: :updated_by_id,
- Name: :name,
- ID: :id,
- ValidID: :active,
- Comment: :note,
- }
- records.each { |priority|
- _set_valid(priority)
- # get new attributes
- priority_new = {
- created_by_id: 1,
- updated_by_id: 1,
- }
- map.each { |key, value|
- next if !priority.key?(key.to_s)
- priority_new[value] = priority[key.to_s]
- }
- # check if state already exists
- priority_old = Ticket::Priority.lookup(id: priority_new[:id])
- # 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
- _reset_pk('ticket_priorities')
- end
- }
- end
- # sync ticket groups / queues
- def self.ticket_group(records)
- map = {
- ChangeTime: :updated_at,
- CreateTime: :created_at,
- CreateBy: :created_by_id,
- ChangeBy: :updated_by_id,
- Name: :name,
- QueueID: :id,
- ValidID: :active,
- Comment: :note,
- }
- records.each { |group|
- _set_valid(group)
- # get new attributes
- group_new = {
- created_by_id: 1,
- updated_by_id: 1,
- }
- map.each { |key, value|
- next if !group.key?(key.to_s)
- group_new[value] = group[key.to_s]
- }
- # check if state already exists
- group_old = Group.lookup(id: group_new[:id])
- # 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
- _reset_pk('groups')
- end
- }
- end
- # sync agents
- def self.user(records, groups, roles, queues)
- 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,
- UserLogin: :login,
- UserPw: :password,
- }
- records.each { |user|
- _set_valid(user)
- # get roles
- role_ids = get_roles_ids(user, groups, roles, queues)
- # get groups
- group_ids = get_queue_ids(user, groups, roles, queues)
- # get new attributes
- user_new = {
- created_by_id: 1,
- updated_by_id: 1,
- source: 'OTRS Import',
- role_ids: role_ids,
- group_ids: group_ids,
- }
- map.each { |key, value|
- next if !user.key?(key.to_s)
- user_new[value] = user[key.to_s]
- }
- # set pw
- if user_new[:password]
- user_new[:password] = "{sha2}#{user_new[:password]}"
- end
- # check if agent already exists
- user_old = User.lookup(id: user_new[:id])
- # check if login is already used
- login_in_use = User.where( "login = ? AND id != #{user_new[:id]}", user_new[:login].downcase ).count
- if login_in_use > 0
- user_new[:login] = "#{user_new[:login]}_#{user_new[:id]}"
- end
- # create / update agent
- if user_old
- log "update User.find(#{user_old[:id]})"
- # only update roles if different (reduce sql statements)
- if user_old.role_ids == user_new[:role_ids]
- user_new.delete(:role_ids)
- end
- user_old.update_attributes(user_new)
- else
- log "add User.find(#{user_new[:id]})"
- user = User.new(user_new)
- user.id = user_new[:id]
- user.save
- _reset_pk('users')
- end
- }
- end
- def self.get_queue_ids(user, _groups, _roles, queues)
- queue_ids = []
- # lookup by groups
- user['GroupIDs'].each {|group_id, permissions|
- queues.each {|queue_lookup|
- next if queue_lookup['GroupID'] != group_id
- next if !permissions
- next if !permissions.include?('rw')
- queue_ids.push queue_lookup['QueueID']
- }
- }
- # lookup by roles
- # roles of user
- # groups of roles
- # queues of group
- queue_ids
- end
- def self.get_roles_ids(user, groups, roles, _queues)
- local_roles = ['Agent']
- local_role_ids = []
- # apply group permissions
- user['GroupIDs'].each {|group_id, permissions|
- groups.each {|group_lookup|
- next if group_id != group_lookup['ID']
- next if !permissions
- if group_lookup['Name'] == 'admin' && permissions.include?('rw')
- local_roles.push 'Admin'
- end
- next if group_lookup['Name'] !~ /^(stats|report)/
- next if !( permissions.include?('ro') || permissions.include?('rw') )
- local_roles.push 'Report'
- }
- }
- # apply role permissions
- user['RoleIDs'].each {|role_id|
- # get groups of role
- roles.each {|role|
- next if role['ID'] != role_id
- # verify group names
- role['GroupIDs'].each {|group_id, permissions|
- groups.each {|group_lookup|
- next if group_id != group_lookup['ID']
- next if !permissions
- if group_lookup['Name'] == 'admin' && permissions.include?('rw')
- local_roles.push 'Admin'
- end
- next if group_lookup['Name'] !~ /^(stats|report)/
- next if !( permissions.include?('ro') || permissions.include?('rw') )
- local_roles.push 'Report'
- }
- }
- }
- }
- local_roles.each {|role|
- role_lookup = Role.lookup(name: role)
- next if !role_lookup
- local_role_ids.push role_lookup.id
- }
- local_role_ids
- end
- # sync customers
- def self.customer(records, organizations)
- 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,
- UserLogin: :login,
- UserPassword: :password,
- UserPhone: :phone,
- UserFax: :fax,
- UserMobile: :mobile,
- UserStreet: :street,
- UserZip: :zip,
- UserCity: :city,
- UserCountry: :country,
- }
- role_agent = Role.lookup(name: 'Agent')
- role_customer = Role.lookup(name: 'Customer')
- records.each { |user|
- _set_valid(user)
- # get new attributes
- user_new = {
- created_by_id: 1,
- updated_by_id: 1,
- source: 'OTRS Import',
- organization_id: get_organization_id(user, organizations),
- role_ids: [ role_customer.id ],
- }
- map.each { |key, value|
- next if !user.key?(key.to_s)
- user_new[value] = user[key.to_s]
- }
- # check if customer already exists
- user_old = User.lookup(login: user_new[:login])
- # create / update agent
- if user_old
- # do not update user if it is already agent
- if !user_old.role_ids.include?(role_agent.id)
- # only update roles if different (reduce sql statements)
- if user_old.role_ids == user_new[:role_ids]
- user_new.delete(:role_ids)
- end
- log "update User.find(#{user_old[:id]})"
- user_old.update_attributes(user_new)
- end
- else
- log "add User.find(#{user_new[:id]})"
- user = User.new(user_new)
- user.save
- _reset_pk('users')
- end
- }
- end
- def self.get_organization_id(user, organizations)
- organization_id = nil
- if user['UserCustomerID']
- organizations.each {|organization|
- next if user['UserCustomerID'] != organization['CustomerID']
- organization = Organization.lookup(name: organization['CustomerCompanyName'])
- organization_id = organization.id
- }
- end
- organization_id
- end
- # sync organizations
- def self.organization(records)
- map = {
- ChangeTime: :updated_at,
- CreateTime: :created_at,
- CreateBy: :created_by_id,
- ChangeBy: :updated_by_id,
- CustomerCompanyName: :name,
- ValidID: :active,
- CustomerCompanyComment: :note,
- }
- records.each { |organization|
- _set_valid(organization)
- # get new attributes
- organization_new = {
- created_by_id: 1,
- updated_by_id: 1,
- }
- map.each { |key, value|
- next if !organization.key?(key.to_s)
- organization_new[value] = organization[key.to_s]
- }
- # check if state already exists
- organization_old = Organization.lookup(name: organization_new[:name])
- # set state types
- if organization_old
- organization_old.update_attributes(organization_new)
- else
- organization = Organization.new(organization_new)
- organization.id = organization_new[:id]
- organization.save
- _reset_pk('organizations')
- end
- }
- end
- # sync settings
- def self.setting(records)
- records.each { |setting|
- # fqdn
- if setting['Key'] == 'FQDN'
- Setting.set('fqdn', setting['Value'])
- end
- # http type
- if setting['Key'] == 'HttpType'
- Setting.set('http_type', setting['Value'])
- end
- # system id
- if setting['Key'] == 'SystemID'
- Setting.set('system_id', setting['Value'])
- end
- # organization
- if setting['Key'] == 'Organization'
- Setting.set('organization', setting['Value'])
- end
- # sending emails
- if setting['Key'] == 'SendmailModule'
- # TODO
- end
- # number generater
- if setting['Key'] == 'Ticket::NumberGenerator'
- if setting['Value'] == 'Kernel::System::Ticket::Number::DateChecksum'
- Setting.set('ticket_number', 'Ticket::Number::Date')
- Setting.set('ticket_number_date', { checksum: true })
- elsif setting['Value'] == 'Kernel::System::Ticket::Number::Date'
- Setting.set('ticket_number', 'Ticket::Number::Date')
- Setting.set('ticket_number_date', { checksum: false })
- end
- end
- # ticket hook
- if setting['Key'] == 'Ticket::Hook'
- Setting.set('ticket_hook', setting['Value'])
- end
- }
- end
- # log
- def self.log(message)
- thread_no = Thread.current[:thread_no] || '-'
- Rails.logger.info "thread##{thread_no}: #{message}"
- end
- # set translate valid ids to active = true|false
- def self._set_valid(record)
- # map
- record['ValidID'] = if record['ValidID'].to_s == '3'
- false
- elsif record['ValidID'].to_s == '2'
- false
- elsif record['ValidID'].to_s == '1'
- true
- elsif record['ValidID'].to_s == '0'
- false
- # fallback
- else
- true
- end
- end
- # cleanup invalid values
- def self._cleanup(record)
- record.each {|key, value|
- if value == '0000-00-00 00:00:00'
- record[key] = nil
- end
- }
- # fix OTRS 3.1 bug, no close time if ticket is created
- if record['StateType'] == 'closed' && (!record['Closed'] || record['Closed'].empty?)
- record['Closed'] = record['Created']
- end
- end
- # utf8 convert
- def self._utf8_encode(data)
- data.each { |key, value|
- next if !value
- next if value.class != String
- data[key] = Encode.conv('utf8', value)
- }
- end
- # reset primary key sequences
- def self._reset_pk(table)
- return if ActiveRecord::Base.connection_config[:adapter] != 'postgresql'
- ActiveRecord::Base.connection.reset_pk_sequence!(table)
- end
- # create customers for article
- def self._article_based_customers(article)
- # create customer/sender if needed
- return if article['sender'] != 'customer'
- return if article['created_by_id'].to_i != 1
- return if article['from'].empty?
- email = nil
- begin
- email = Mail::Address.new(article['from']).address
- rescue
- email = article['from']
- if article['from'] =~ /<(.+?)>/
- email = $1
- end
- end
- user = User.lookup(email: email)
- if !user
- user = User.lookup(login: email)
- end
- if !user
- begin
- display_name = Mail::Address.new( article['from'] ).display_name ||
- ( Mail::Address.new( article['from'] ).comments && Mail::Address.new( article['from'] ).comments[0] )
- rescue
- display_name = article['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')
- begin
- 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,
- )
- rescue ActiveRecord::RecordNotUnique
- log "User #{email} was handled by another thread, taking this."
- user = User.lookup(login: email)
- if !user
- log "User #{email} wasn't created sleep and retry."
- sleep rand 3
- retry
- end
- end
- end
- article['created_by_id'] = user.id
- true
- end
- end
|