otrs.rb 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331
  1. require 'base64'
  2. module Import
  3. end
  4. module Import::OTRS
  5. =begin
  6. result = request_json( :Subaction => 'List', 1)
  7. return
  8. { some json structure }
  9. result = request_json( :Subaction => 'List' )
  10. return
  11. "some data string"
  12. =end
  13. def self.request_json(data, data_only = false)
  14. response = post(data)
  15. if !response
  16. fail "Can't connect to Zammad Migrator"
  17. end
  18. if !response.success?
  19. fail "Can't connect to Zammad Migrator"
  20. end
  21. result = json(response)
  22. if !result
  23. fail 'Invalid response'
  24. end
  25. if data_only
  26. result['Result']
  27. else
  28. result
  29. end
  30. end
  31. =begin
  32. start get request to backend, add auth data automatically
  33. result = request('Subaction=List')
  34. return
  35. "some data string"
  36. =end
  37. def self.request(part)
  38. url = Setting.get('import_otrs_endpoint') + part + ';Key=' + Setting.get('import_otrs_endpoint_key')
  39. log 'GET: ' + url
  40. response = UserAgent.get(
  41. url,
  42. {},
  43. {
  44. open_timeout: 10,
  45. read_timeout: 60,
  46. user: Setting.get('import_otrs_user'),
  47. password: Setting.get('import_otrs_password'),
  48. },
  49. )
  50. if !response.success?
  51. log "ERROR: #{response.error}"
  52. return
  53. end
  54. response
  55. end
  56. =begin
  57. start post request to backend, add auth data automatically
  58. result = request('Subaction=List')
  59. return
  60. "some data string"
  61. =end
  62. def self.post(data, url = nil)
  63. if !url
  64. url = Setting.get('import_otrs_endpoint')
  65. data['Action'] = 'ZammadMigrator'
  66. end
  67. data['Key'] = Setting.get('import_otrs_endpoint_key')
  68. log 'POST: ' + url
  69. log 'PARAMS: ' + data.inspect
  70. open_timeout = 10
  71. read_timeout = 120
  72. if data.empty?
  73. open_timeout = 6
  74. read_timeout = 20
  75. end
  76. response = UserAgent.post(
  77. url,
  78. data,
  79. {
  80. open_timeout: open_timeout,
  81. read_timeout: read_timeout,
  82. user: Setting.get('import_otrs_user'),
  83. password: Setting.get('import_otrs_password'),
  84. },
  85. )
  86. if !response.success?
  87. log "ERROR: #{response.error}"
  88. return
  89. end
  90. response
  91. end
  92. =begin
  93. start post request to backend, add auth data automatically
  94. result = json('some response string')
  95. return
  96. {}
  97. =end
  98. def self.json(response)
  99. data = Encode.conv( 'utf8', response.body.to_s )
  100. JSON.parse( data )
  101. end
  102. =begin
  103. start auth on OTRS - just for experimental reasons
  104. result = auth(username, password)
  105. return
  106. { ..user structure.. }
  107. =end
  108. def self.auth(username, password)
  109. url = Setting.get('import_otrs_endpoint')
  110. url.gsub!('ZammadMigrator', 'ZammadSSO')
  111. response = post( { Action: 'ZammadSSO', Subaction: 'Auth', User: username, Pw: password }, url )
  112. return if !response
  113. return if !response.success?
  114. result = json(response)
  115. result
  116. end
  117. =begin
  118. request session data - just for experimental reasons
  119. result = session(session_id)
  120. return
  121. { ..session structure.. }
  122. =end
  123. def self.session(session_id)
  124. url = Setting.get('import_otrs_endpoint')
  125. url.gsub!('ZammadMigrator', 'ZammadSSO')
  126. response = post( { Action: 'ZammadSSO', Subaction: 'SessionCheck', SessionID: session_id }, url )
  127. return if !response
  128. return if !response.success?
  129. result = json(response)
  130. result
  131. end
  132. =begin
  133. load objects from otrs
  134. result = load('SysConfig')
  135. return
  136. [
  137. { ..object1.. },
  138. { ..object2.. },
  139. { ..object3.. },
  140. ]
  141. =end
  142. def self.load( object, limit = '', offset = '', diff = 0 )
  143. request_json( { Subaction: 'Export', Object: object, Limit: limit, Offset: offset, Diff: diff }, 1 )
  144. end
  145. =begin
  146. start get request to backend to check connection
  147. result = connection_test
  148. return
  149. true | false
  150. =end
  151. def self.connection_test
  152. request_json({})
  153. end
  154. =begin
  155. get object statistic from server ans save it in cache
  156. result = statistic('Subaction=List')
  157. return
  158. {
  159. 'Ticket' => 1234,
  160. 'User' => 123,
  161. 'SomeObject' => 999,
  162. }
  163. =end
  164. def self.statistic
  165. # check cache
  166. cache = Cache.get('import_otrs_stats')
  167. if cache
  168. return cache
  169. end
  170. # retrive statistic
  171. statistic = request_json( { Subaction: 'List' }, 1)
  172. if statistic
  173. Cache.write('import_otrs_stats', statistic)
  174. end
  175. statistic
  176. end
  177. =begin
  178. return current import state
  179. result = current_state
  180. return
  181. {
  182. :Ticket => {
  183. :total => 1234,
  184. :done => 13,
  185. },
  186. :Base => {
  187. :total => 1234,
  188. :done => 13,
  189. },
  190. }
  191. =end
  192. def self.current_state
  193. data = statistic
  194. base = Group.count + Ticket::State.count + Ticket::Priority.count
  195. base_total = data['Queue'] + data['State'] + data['Priority']
  196. user = User.count
  197. user_total = data['User'] + data['CustomerUser']
  198. data = {
  199. Base: {
  200. done: base,
  201. total: base_total || 0,
  202. },
  203. User: {
  204. done: user,
  205. total: user_total || 0,
  206. },
  207. Ticket: {
  208. done: Ticket.count,
  209. total: data['Ticket'] || 0,
  210. },
  211. }
  212. data
  213. end
  214. #
  215. # start import
  216. #
  217. # Import::OTRS.start
  218. #
  219. def self.start
  220. log 'Start import...'
  221. # check if system is in import mode
  222. if !Setting.get('import_mode')
  223. fail 'System is not in import mode!'
  224. end
  225. result = request_json({})
  226. if !result['Success']
  227. 'API key not valid!'
  228. end
  229. # set settings
  230. settings = load('SysConfig')
  231. setting(settings)
  232. # dynamic fields
  233. dynamic_fields = load('DynamicField')
  234. #settings(dynamic_fields, settings)
  235. # email accounts
  236. #accounts = load('PostMasterAccount')
  237. #account(accounts)
  238. # email filter
  239. #filters = load('PostMasterFilter')
  240. #filter(filters)
  241. # create states
  242. states = load('State')
  243. ActiveRecord::Base.transaction do
  244. state(states)
  245. end
  246. # create priorities
  247. priorities = load('Priority')
  248. ActiveRecord::Base.transaction do
  249. priority(priorities)
  250. end
  251. # create groups
  252. queues = load('Queue')
  253. ActiveRecord::Base.transaction do
  254. ticket_group(queues)
  255. end
  256. # get agents groups
  257. groups = load('Group')
  258. # get agents roles
  259. roles = load('Role')
  260. # create agents
  261. users = load('User')
  262. ActiveRecord::Base.transaction do
  263. user(users, groups, roles, queues)
  264. end
  265. # create organizations
  266. organizations = load('Customer')
  267. ActiveRecord::Base.transaction do
  268. organization(organizations)
  269. end
  270. # create customers
  271. count = 0
  272. steps = 50
  273. run = true
  274. while run
  275. count += steps
  276. records = load('CustomerUser', steps, count - steps)
  277. if !records || !records[0]
  278. log 'all customers imported.'
  279. run = false
  280. next
  281. end
  282. customer(records, organizations)
  283. end
  284. Thread.abort_on_exception = true
  285. thread_count = 8
  286. threads = {}
  287. count = 0
  288. locks = { User: {} }
  289. (1..thread_count).each {|thread|
  290. threads[thread] = Thread.new {
  291. Thread.current[:thread_no] = thread
  292. sleep thread * 3
  293. log "Started import thread# #{thread} ..."
  294. steps = 20
  295. loop do
  296. count += steps
  297. log "loading... thread# #{thread} ..."
  298. offset = count - steps
  299. if offset != 0
  300. offset = count - steps + 1
  301. end
  302. records = load( 'Ticket', steps, count - steps)
  303. if !records || !records[0]
  304. log "... thread# #{thread}, no more work."
  305. break
  306. end
  307. _ticket_result(records, locks, thread)
  308. end
  309. ActiveRecord::Base.connection.close
  310. }
  311. }
  312. (1..thread_count).each {|thread|
  313. threads[thread].join
  314. }
  315. Setting.set( 'system_init_done', true )
  316. #Setting.set( 'import_mode', false )
  317. true
  318. end
  319. def self.diff_worker
  320. return if !Setting.get('import_mode')
  321. return if Setting.get('import_otrs_endpoint') == 'http://otrs_host/otrs'
  322. diff
  323. end
  324. def self.diff
  325. log 'Start diff...'
  326. # check if system is in import mode
  327. if !Setting.get('import_mode')
  328. fail 'System is not in import mode!'
  329. end
  330. # create states
  331. states = load('State')
  332. state(states)
  333. # create priorities
  334. priorities = load('Priority')
  335. priority(priorities)
  336. # create groups
  337. queues = load('Queue')
  338. ticket_group(queues)
  339. # get agents groups
  340. groups = load('Group')
  341. # get agents roles
  342. roles = load('Role')
  343. # create agents
  344. users = load('User')
  345. user(users, groups, roles, queues)
  346. # create organizations
  347. organizations = load('Customer')
  348. organization(organizations)
  349. # get changed tickets
  350. ticket_diff
  351. end
  352. def self.ticket_diff
  353. count = 0
  354. run = true
  355. steps = 20
  356. locks = { User: {} }
  357. while run
  358. count += steps
  359. log 'loading... diff ...'
  360. offset = count - steps
  361. if offset != 0
  362. offset = count - steps + 1
  363. end
  364. records = load( 'Ticket', steps, count - steps, 1 )
  365. if !records || !records[0]
  366. log '... no more work.'
  367. run = false
  368. next
  369. end
  370. _ticket_result(records, locks)
  371. end
  372. end
  373. def self._ticket_result(result, locks, _thread = '-')
  374. map = {
  375. Ticket: {
  376. Changed: :updated_at,
  377. Created: :created_at,
  378. CreateBy: :created_by_id,
  379. TicketNumber: :number,
  380. QueueID: :group_id,
  381. StateID: :state_id,
  382. PriorityID: :priority_id,
  383. Owner: :owner,
  384. CustomerUserID: :customer,
  385. Title: :title,
  386. TicketID: :id,
  387. FirstResponse: :first_response,
  388. #FirstResponseTimeDestinationDate: :first_response_escal_date,
  389. #FirstResponseInMin: :first_response_in_min,
  390. #FirstResponseDiffInMin: :first_response_diff_in_min,
  391. Closed: :close_time,
  392. #SoltutionTimeDestinationDate: :close_time_escal_date,
  393. #CloseTimeInMin: :close_time_in_min,
  394. #CloseTimeDiffInMin: :close_time_diff_in_min,
  395. },
  396. Article: {
  397. SenderType: :sender,
  398. ArticleType: :type,
  399. TicketID: :ticket_id,
  400. ArticleID: :id,
  401. Body: :body,
  402. From: :from,
  403. To: :to,
  404. Cc: :cc,
  405. Subject: :subject,
  406. InReplyTo: :in_reply_to,
  407. MessageID: :message_id,
  408. #ReplyTo: :reply_to,
  409. References: :references,
  410. Changed: :updated_at,
  411. Created: :created_at,
  412. ChangedBy: :updated_by_id,
  413. CreatedBy: :created_by_id,
  414. },
  415. }
  416. result.each {|record|
  417. # cleanup values
  418. _cleanup(record)
  419. _utf8_encode(record)
  420. ticket_new = {
  421. title: '',
  422. created_by_id: 1,
  423. updated_by_id: 1,
  424. }
  425. map[:Ticket].each { |key, value|
  426. next if !record.key?(key.to_s)
  427. ticket_new[value] = record[key.to_s]
  428. }
  429. ticket_old = Ticket.where( id: ticket_new[:id] ).first
  430. # find owner
  431. if ticket_new[:owner]
  432. user = User.lookup( login: ticket_new[:owner].downcase )
  433. if user
  434. ticket_new[:owner_id] = user.id
  435. else
  436. ticket_new[:owner_id] = 1
  437. end
  438. ticket_new.delete(:owner)
  439. end
  440. # find customer
  441. if ticket_new[:customer]
  442. user = User.lookup( login: ticket_new[:customer].downcase )
  443. if user
  444. ticket_new[:customer_id] = user.id
  445. else
  446. ticket_new[:customer_id] = 1
  447. end
  448. ticket_new.delete(:customer)
  449. else
  450. ticket_new[:customer_id] = 1
  451. end
  452. # set state types
  453. if ticket_old
  454. log "update Ticket.find(#{ticket_new[:id]})"
  455. ticket_old.update_attributes(ticket_new)
  456. else
  457. log "add Ticket.find(#{ticket_new[:id]})"
  458. ticket = Ticket.new(ticket_new)
  459. ticket.id = ticket_new[:id]
  460. ticket.save
  461. end
  462. # utf8 encode
  463. record['Articles'].each { |article|
  464. _utf8_encode(article)
  465. }
  466. # lookup customers to create first
  467. record['Articles'].each { |article|
  468. _article_based_customers(article, locks)
  469. }
  470. ActiveRecord::Base.transaction do
  471. record['Articles'].each { |article|
  472. # get article values
  473. article_new = {
  474. created_by_id: 1,
  475. updated_by_id: 1,
  476. }
  477. map[:Article].each { |key, value|
  478. next if !article.key?(key.to_s)
  479. article_new[value] = article[key.to_s]
  480. }
  481. if article_new[:sender] == 'customer'
  482. article_new[:sender_id] = Ticket::Article::Sender.lookup( name: 'Customer' ).id
  483. article_new.delete( :sender )
  484. end
  485. if article_new[:sender] == 'agent'
  486. article_new[:sender_id] = Ticket::Article::Sender.lookup( name: 'Agent' ).id
  487. article_new.delete( :sender )
  488. end
  489. if article_new[:sender] == 'system'
  490. article_new[:sender_id] = Ticket::Article::Sender.lookup( name: 'System' ).id
  491. article_new.delete( :sender )
  492. end
  493. if article_new[:type] == 'email-external'
  494. article_new[:type_id] = Ticket::Article::Type.lookup( name: 'email' ).id
  495. article_new[:internal] = false
  496. elsif article_new[:type] == 'email-internal'
  497. article_new[:type_id] = Ticket::Article::Type.lookup( name: 'email' ).id
  498. article_new[:internal] = true
  499. elsif article_new[:type] == 'note-external'
  500. article_new[:type_id] = Ticket::Article::Type.lookup( name: 'note' ).id
  501. article_new[:internal] = false
  502. elsif article_new[:type] == 'note-internal'
  503. article_new[:type_id] = Ticket::Article::Type.lookup( name: 'note' ).id
  504. article_new[:internal] = true
  505. elsif article_new[:type] == 'phone'
  506. article_new[:type_id] = Ticket::Article::Type.lookup( name: 'phone' ).id
  507. article_new[:internal] = false
  508. elsif article_new[:type] == 'webrequest'
  509. article_new[:type_id] = Ticket::Article::Type.lookup( name: 'web' ).id
  510. article_new[:internal] = false
  511. else
  512. article_new[:type_id] = 9
  513. end
  514. article_new.delete( :type )
  515. article_object = Ticket::Article.find_by( id: article_new[:id] )
  516. # set state types
  517. if article_object
  518. log "update Ticket::Article.find(#{article_new[:id]})"
  519. article_object.update_attributes(article_new)
  520. else
  521. log "add Ticket::Article.find(#{article_new[:id]})"
  522. article_object = Ticket::Article.new(article_new)
  523. article_object.id = article_new[:id]
  524. article_object.save
  525. end
  526. next if !article['Attachments']
  527. next if article['Attachments'].empty?
  528. # TODO: refactor
  529. # check if there are attachments present
  530. if !article_object.attachments.empty?
  531. # skip attachments if count is equal
  532. next if article_object.attachments.count == article['Attachments'].count
  533. # if the count differs delete all so we
  534. # can have a fresh start
  535. article_object.attachments.each(&:delete)
  536. end
  537. # import article attachments
  538. article['Attachments'].each { |attachment|
  539. Store.add(
  540. object: 'Ticket::Article',
  541. o_id: article_object.id,
  542. filename: Base64.decode64(attachment['Filename']),
  543. data: Base64.decode64(attachment['Content']),
  544. preferences: {
  545. content_type: attachment['ContentType'],
  546. content_id: attachment['ContentID'],
  547. :'content-alternative' => attachment['ContentAlternative'],
  548. },
  549. created_by_id: 1,
  550. )
  551. }
  552. }
  553. end
  554. #puts "HS: #{record['History'].inspect}"
  555. record['History'].each { |history|
  556. if history['HistoryType'] == 'NewTicket'
  557. #puts "HS.add( #{history.inspect} )"
  558. res = History.add(
  559. id: history['HistoryID'],
  560. o_id: history['TicketID'],
  561. history_type: 'created',
  562. history_object: 'Ticket',
  563. created_at: history['CreateTime'],
  564. created_by_id: history['CreateBy']
  565. )
  566. #puts "res #{res.inspect}"
  567. end
  568. if history['HistoryType'] == 'StateUpdate'
  569. data = history['Name']
  570. # "%%new%%open%%"
  571. from = nil
  572. to = nil
  573. if data =~ /%%(.+?)%%(.+?)%%/
  574. from = $1
  575. to = $2
  576. state_from = Ticket::State.lookup( name: from )
  577. state_to = Ticket::State.lookup( name: to )
  578. if state_from
  579. from_id = state_from.id
  580. end
  581. if state_to
  582. to_id = state_to.id
  583. end
  584. end
  585. History.add(
  586. id: history['HistoryID'],
  587. o_id: history['TicketID'],
  588. history_type: 'updated',
  589. history_object: 'Ticket',
  590. history_attribute: 'state',
  591. value_from: from,
  592. id_from: from_id,
  593. value_to: to,
  594. id_to: to_id,
  595. created_at: history['CreateTime'],
  596. created_by_id: history['CreateBy']
  597. )
  598. end
  599. if history['HistoryType'] == 'Move'
  600. data = history['Name']
  601. # "%%Queue1%%5%%Postmaster%%1"
  602. from = nil
  603. to = nil
  604. if data =~ /%%(.+?)%%(.+?)%%(.+?)%%(.+?)$/
  605. from = $1
  606. from_id = $2
  607. to = $3
  608. to_id = $4
  609. end
  610. History.add(
  611. id: history['HistoryID'],
  612. o_id: history['TicketID'],
  613. history_type: 'updated',
  614. history_object: 'Ticket',
  615. history_attribute: 'group',
  616. value_from: from,
  617. value_to: to,
  618. id_from: from_id,
  619. id_to: to_id,
  620. created_at: history['CreateTime'],
  621. created_by_id: history['CreateBy']
  622. )
  623. end
  624. if history['HistoryType'] == 'PriorityUpdate'
  625. data = history['Name']
  626. # "%%3 normal%%3%%5 very high%%5"
  627. from = nil
  628. to = nil
  629. if data =~ /%%(.+?)%%(.+?)%%(.+?)%%(.+?)$/
  630. from = $1
  631. from_id = $2
  632. to = $3
  633. to_id = $4
  634. end
  635. History.add(
  636. id: history['HistoryID'],
  637. o_id: history['TicketID'],
  638. history_type: 'updated',
  639. history_object: 'Ticket',
  640. history_attribute: 'priority',
  641. value_from: from,
  642. value_to: to,
  643. id_from: from_id,
  644. id_to: to_id,
  645. created_at: history['CreateTime'],
  646. created_by_id: history['CreateBy']
  647. )
  648. end
  649. next if !history['ArticleID']
  650. next if history['ArticleID'] == 0
  651. History.add(
  652. id: history['HistoryID'],
  653. o_id: history['ArticleID'],
  654. history_type: 'created',
  655. history_object: 'Ticket::Article',
  656. related_o_id: history['TicketID'],
  657. related_history_object: 'Ticket',
  658. created_at: history['CreateTime'],
  659. created_by_id: history['CreateBy']
  660. )
  661. }
  662. }
  663. end
  664. # sync ticket states
  665. def self.state(records)
  666. map = {
  667. ChangeTime: :updated_at,
  668. CreateTime: :created_at,
  669. CreateBy: :created_by_id,
  670. ChangeBy: :updated_by_id,
  671. Name: :name,
  672. ID: :id,
  673. ValidID: :active,
  674. Comment: :note,
  675. }
  676. # rename states to handle not uniq issues
  677. Ticket::State.all.each {|state|
  678. state.name = state.name + '_tmp'
  679. state.save
  680. }
  681. records.each { |state|
  682. _set_valid(state)
  683. # get new attributes
  684. state_new = {
  685. created_by_id: 1,
  686. updated_by_id: 1,
  687. }
  688. map.each { |key, value|
  689. next if !state.key?(key.to_s)
  690. state_new[value] = state[key.to_s]
  691. }
  692. # check if state already exists
  693. state_old = Ticket::State.where( id: state_new[:id] ).first
  694. # set state types
  695. if state['TypeName'] == 'pending auto'
  696. state['TypeName'] = 'pending action'
  697. end
  698. state_type = Ticket::StateType.where( name: state['TypeName'] ).first
  699. state_new[:state_type_id] = state_type.id
  700. if state_old
  701. state_old.update_attributes(state_new)
  702. else
  703. state = Ticket::State.new(state_new)
  704. state.id = state_new[:id]
  705. state.save
  706. end
  707. }
  708. end
  709. # sync ticket priorities
  710. def self.priority(records)
  711. map = {
  712. ChangeTime: :updated_at,
  713. CreateTime: :created_at,
  714. CreateBy: :created_by_id,
  715. ChangeBy: :updated_by_id,
  716. Name: :name,
  717. ID: :id,
  718. ValidID: :active,
  719. Comment: :note,
  720. }
  721. records.each { |priority|
  722. _set_valid(priority)
  723. # get new attributes
  724. priority_new = {
  725. created_by_id: 1,
  726. updated_by_id: 1,
  727. }
  728. map.each { |key, value|
  729. next if !priority.key?(key.to_s)
  730. priority_new[value] = priority[key.to_s]
  731. }
  732. # check if state already exists
  733. priority_old = Ticket::Priority.where( id: priority_new[:id] ).first
  734. # set state types
  735. if priority_old
  736. priority_old.update_attributes(priority_new)
  737. else
  738. priority = Ticket::Priority.new(priority_new)
  739. priority.id = priority_new[:id]
  740. priority.save
  741. end
  742. }
  743. end
  744. # sync ticket groups / queues
  745. def self.ticket_group(records)
  746. map = {
  747. ChangeTime: :updated_at,
  748. CreateTime: :created_at,
  749. CreateBy: :created_by_id,
  750. ChangeBy: :updated_by_id,
  751. Name: :name,
  752. QueueID: :id,
  753. ValidID: :active,
  754. Comment: :note,
  755. }
  756. records.each { |group|
  757. _set_valid(group)
  758. # get new attributes
  759. group_new = {
  760. created_by_id: 1,
  761. updated_by_id: 1,
  762. }
  763. map.each { |key, value|
  764. next if !group.key?(key.to_s)
  765. group_new[value] = group[key.to_s]
  766. }
  767. # check if state already exists
  768. group_old = Group.where( id: group_new[:id] ).first
  769. # set state types
  770. if group_old
  771. group_old.update_attributes(group_new)
  772. else
  773. group = Group.new(group_new)
  774. group.id = group_new[:id]
  775. group.save
  776. end
  777. }
  778. end
  779. # sync agents
  780. def self.user(records, groups, roles, queues)
  781. map = {
  782. ChangeTime: :updated_at,
  783. CreateTime: :created_at,
  784. CreateBy: :created_by_id,
  785. ChangeBy: :updated_by_id,
  786. UserID: :id,
  787. ValidID: :active,
  788. Comment: :note,
  789. UserEmail: :email,
  790. UserFirstname: :firstname,
  791. UserLastname: :lastname,
  792. UserLogin: :login,
  793. UserPw: :password,
  794. }
  795. records.each { |user|
  796. _set_valid(user)
  797. # get roles
  798. role_ids = get_roles_ids(user, groups, roles, queues)
  799. # get groups
  800. group_ids = get_queue_ids(user, groups, roles, queues)
  801. # get new attributes
  802. user_new = {
  803. created_by_id: 1,
  804. updated_by_id: 1,
  805. source: 'OTRS Import',
  806. role_ids: role_ids,
  807. group_ids: group_ids,
  808. }
  809. map.each { |key, value|
  810. next if !user.key?(key.to_s)
  811. user_new[value] = user[key.to_s]
  812. }
  813. # set pw
  814. if user_new[:password]
  815. user_new[:password] = "{sha2}#{user_new[:password]}"
  816. end
  817. # check if agent already exists
  818. user_old = User.where( id: user_new[:id] ).first
  819. # check if login is already used
  820. login_in_use = User.where( "login = ? AND id != #{user_new[:id]}", user_new[:login].downcase ).count
  821. if login_in_use > 0
  822. user_new[:login] = "#{user_new[:login]}_#{user_new[:id]}"
  823. end
  824. # create / update agent
  825. if user_old
  826. log "update User.find(#{user_old[:id]})"
  827. # only update roles if different (reduce sql statements)
  828. if user_old.role_ids == user_new[:role_ids]
  829. user_new.delete( :role_ids )
  830. end
  831. user_old.update_attributes(user_new)
  832. else
  833. log "add User.find(#{user_new[:id]})"
  834. user = User.new(user_new)
  835. user.id = user_new[:id]
  836. user.save
  837. end
  838. }
  839. end
  840. def self.get_queue_ids(user, _groups, _roles, queues)
  841. queue_ids = []
  842. # lookup by groups
  843. user['GroupIDs'].each {|group_id, permissions|
  844. queues.each {|queue_lookup|
  845. next if queue_lookup['GroupID'] != group_id
  846. next if !permissions
  847. next if !permissions.include?('rw')
  848. queue_ids.push queue_lookup['QueueID']
  849. }
  850. }
  851. # lookup by roles
  852. # roles of user
  853. # groups of roles
  854. # queues of group
  855. queue_ids
  856. end
  857. def self.get_roles_ids(user, groups, roles, _queues)
  858. roles = ['Agent']
  859. role_ids = []
  860. user['GroupIDs'].each {|group_id, permissions|
  861. groups.each {|group_lookup|
  862. next if group_id != group_lookup['ID']
  863. next if !permissions
  864. if group_lookup['Name'] == 'admin' && permissions.include?('rw')
  865. roles.push 'Admin'
  866. end
  867. next if group_lookup['Name'] !~ /^(stats|report)/
  868. next if !( permissions.include?('ro') || permissions.include?('rw') )
  869. roles.push 'Report'
  870. }
  871. }
  872. roles.each {|role|
  873. role_lookup = Role.lookup( name: role )
  874. next if !role_lookup
  875. role_ids.push role_lookup.id
  876. }
  877. role_ids
  878. end
  879. # sync customers
  880. def self.customer(records, organizations)
  881. map = {
  882. ChangeTime: :updated_at,
  883. CreateTime: :created_at,
  884. CreateBy: :created_by_id,
  885. ChangeBy: :updated_by_id,
  886. ValidID: :active,
  887. UserComment: :note,
  888. UserEmail: :email,
  889. UserFirstname: :firstname,
  890. UserLastname: :lastname,
  891. UserLogin: :login,
  892. UserPassword: :password,
  893. UserPhone: :phone,
  894. UserFax: :fax,
  895. UserMobile: :mobile,
  896. UserStreet: :street,
  897. UserZip: :zip,
  898. UserCity: :city,
  899. UserCountry: :country,
  900. }
  901. role_agent = Role.lookup( name: 'Agent' )
  902. role_customer = Role.lookup( name: 'Customer' )
  903. records.each { |user|
  904. _set_valid(user)
  905. # get new attributes
  906. user_new = {
  907. created_by_id: 1,
  908. updated_by_id: 1,
  909. source: 'OTRS Import',
  910. organization_id: get_organization_id(user, organizations),
  911. role_ids: [ role_customer.id ],
  912. }
  913. map.each { |key, value|
  914. next if !user.key?(key.to_s)
  915. user_new[value] = user[key.to_s]
  916. }
  917. # check if customer already exists
  918. user_old = User.where( login: user_new[:login] ).first
  919. # create / update agent
  920. if user_old
  921. # do not update user if it is already agent
  922. if !user_old.role_ids.include?( role_agent.id )
  923. # only update roles if different (reduce sql statements)
  924. if user_old.role_ids == user_new[:role_ids]
  925. user_new.delete( :role_ids )
  926. end
  927. log "update User.find(#{user_old[:id]})"
  928. user_old.update_attributes(user_new)
  929. end
  930. else
  931. log "add User.find(#{user_new[:id]})"
  932. user = User.new(user_new)
  933. user.save
  934. end
  935. }
  936. end
  937. def self.get_organization_id(user, organizations)
  938. organization_id = nil
  939. if user['UserCustomerID']
  940. organizations.each {|organization|
  941. next if user['UserCustomerID'] != organization['CustomerID']
  942. organization = Organization.where(name: organization['CustomerCompanyName'] ).first
  943. organization_id = organization.id
  944. }
  945. end
  946. organization_id
  947. end
  948. # sync organizations
  949. def self.organization(records)
  950. map = {
  951. ChangeTime: :updated_at,
  952. CreateTime: :created_at,
  953. CreateBy: :created_by_id,
  954. ChangeBy: :updated_by_id,
  955. CustomerCompanyName: :name,
  956. ValidID: :active,
  957. CustomerCompanyComment: :note,
  958. }
  959. records.each { |organization|
  960. _set_valid(organization)
  961. # get new attributes
  962. organization_new = {
  963. created_by_id: 1,
  964. updated_by_id: 1,
  965. }
  966. map.each { |key, value|
  967. next if !organization.key?(key.to_s)
  968. organization_new[value] = organization[key.to_s]
  969. }
  970. # check if state already exists
  971. organization_old = Organization.where( name: organization_new[:name] ).first
  972. # set state types
  973. if organization_old
  974. organization_old.update_attributes(organization_new)
  975. else
  976. organization = Organization.new(organization_new)
  977. organization.id = organization_new[:id]
  978. organization.save
  979. end
  980. }
  981. end
  982. # sync settings
  983. def self.setting(records)
  984. records.each { |setting|
  985. # fqdn
  986. if setting['Key'] == 'FQDN'
  987. Setting.set( 'fqdn', setting['Value'] )
  988. end
  989. # http type
  990. if setting['Key'] == 'HttpType'
  991. Setting.set( 'http_type', setting['Value'] )
  992. end
  993. # system id
  994. if setting['Key'] == 'SystemID'
  995. Setting.set( 'system_id', setting['Value'] )
  996. end
  997. # organization
  998. if setting['Key'] == 'Organization'
  999. Setting.set( 'organization', setting['Value'] )
  1000. end
  1001. # sending emails
  1002. if setting['Key'] == 'SendmailModule'
  1003. # TODO
  1004. end
  1005. # number generater
  1006. if setting['Key'] == 'Ticket::NumberGenerator'
  1007. if setting['Value'] == 'Kernel::System::Ticket::Number::DateChecksum'
  1008. Setting.set( 'ticket_number', 'Ticket::Number::Date' )
  1009. Setting.set( 'ticket_number_date', { checksum: true } )
  1010. elsif setting['Value'] == 'Kernel::System::Ticket::Number::Date'
  1011. Setting.set( 'ticket_number', 'Ticket::Number::Date' )
  1012. Setting.set( 'ticket_number_date', { checksum: false } )
  1013. end
  1014. end
  1015. # ticket hook
  1016. if setting['Key'] == 'Ticket::Hook'
  1017. Setting.set( 'ticket_hook', setting['Value'] )
  1018. end
  1019. }
  1020. end
  1021. # log
  1022. def self.log(message)
  1023. thread_no = Thread.current[:thread_no] || '-'
  1024. Rails.logger.info "thread##{thread_no}: #{message}"
  1025. end
  1026. # set translate valid ids to active = true|false
  1027. def self._set_valid(record)
  1028. # map
  1029. if record['ValidID'].to_s == '3'
  1030. record['ValidID'] = false
  1031. elsif record['ValidID'].to_s == '2'
  1032. record['ValidID'] = false
  1033. elsif record['ValidID'].to_s == '1'
  1034. record['ValidID'] = true
  1035. elsif record['ValidID'].to_s == '0'
  1036. record['ValidID'] = false
  1037. # fallback
  1038. else
  1039. record['ValidID'] = true
  1040. end
  1041. end
  1042. # cleanup invalid values
  1043. def self._cleanup(record)
  1044. record.each {|key, value|
  1045. if value == '0000-00-00 00:00:00'
  1046. record[key] = nil
  1047. end
  1048. }
  1049. # fix OTRS 3.1 bug, no close time if ticket is created
  1050. if record['StateType'] == 'closed' && ( !record['Closed'] || record['Closed'].empty? )
  1051. record['Closed'] = record['Created']
  1052. end
  1053. end
  1054. # utf8 convert
  1055. def self._utf8_encode(data)
  1056. data.each { |key, value|
  1057. next if !value
  1058. next if value.class != String
  1059. data[key] = Encode.conv( 'utf8', value )
  1060. }
  1061. end
  1062. # create customers for article
  1063. def self._article_based_customers(article, locks)
  1064. # create customer/sender if needed
  1065. return if article['sender'] != 'customer'
  1066. return if article['created_by_id'].to_i != 1
  1067. return if article['from'].empty?
  1068. email = nil
  1069. begin
  1070. email = Mail::Address.new( article['from'] ).address
  1071. rescue
  1072. email = article['from']
  1073. if article['from'] =~ /<(.+?)>/
  1074. email = $1
  1075. end
  1076. end
  1077. # create article user if not exists
  1078. while locks[:User][ email ]
  1079. log "user #{email} is locked"
  1080. sleep 1
  1081. end
  1082. # lock user
  1083. locks[:User][ email ] = true
  1084. user = User.where( email: email ).first
  1085. if !user
  1086. user = User.where( login: email ).first
  1087. end
  1088. if !user
  1089. begin
  1090. display_name = Mail::Address.new( article['from'] ).display_name ||
  1091. ( Mail::Address.new( article['from'] ).comments && Mail::Address.new( article['from'] ).comments[0] )
  1092. rescue
  1093. display_name = article['from']
  1094. end
  1095. # do extra decoding because we needed to use field.value
  1096. display_name = Mail::Field.new( 'X-From', display_name ).to_s
  1097. roles = Role.lookup( name: 'Customer' )
  1098. user = User.create(
  1099. login: email,
  1100. firstname: display_name,
  1101. lastname: '',
  1102. email: email,
  1103. password: '',
  1104. active: true,
  1105. role_ids: [roles.id],
  1106. updated_by_id: 1,
  1107. created_by_id: 1,
  1108. )
  1109. end
  1110. article['created_by_id'] = user.id
  1111. # unlock user
  1112. locks[:User][ email ] = false
  1113. true
  1114. end
  1115. end