otrs.rb 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380
  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. fail '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. steps = 20
  288. (1..thread_count).each { |thread|
  289. threads[thread] = Thread.new {
  290. log "Started import thread# #{thread} ..."
  291. Thread.current[:thread_no] = thread
  292. Thread.current[:loop_count] = 0
  293. loop do
  294. # get the offset for the current thread and loop count
  295. thread_offset_base = (Thread.current[:thread_no] - 1) * steps
  296. thread_step = thread_count * steps
  297. offset = Thread.current[:loop_count] * thread_step + thread_offset_base
  298. log "loading... thread# #{thread} ..."
  299. records = load( 'Ticket', steps, offset)
  300. if !records || !records[0]
  301. log "... thread# #{thread}, no more work."
  302. break
  303. end
  304. _ticket_result(records, thread)
  305. Thread.current[:loop_count] += 1
  306. end
  307. ActiveRecord::Base.connection.close
  308. }
  309. }
  310. (1..thread_count).each {|thread|
  311. threads[thread].join
  312. }
  313. Setting.set( 'system_init_done', true )
  314. #Setting.set( 'import_mode', false )
  315. true
  316. end
  317. def self.diff_worker
  318. return if !Setting.get('import_mode')
  319. return if Setting.get('import_otrs_endpoint') == 'http://otrs_host/otrs'
  320. diff
  321. end
  322. def self.diff
  323. log 'Start diff...'
  324. # check if system is in import mode
  325. if !Setting.get('import_mode')
  326. fail 'System is not in import mode!'
  327. end
  328. # create states
  329. states = load('State')
  330. state(states)
  331. # create priorities
  332. priorities = load('Priority')
  333. priority(priorities)
  334. # create groups
  335. queues = load('Queue')
  336. ticket_group(queues)
  337. # get agents groups
  338. groups = load('Group')
  339. # get agents roles
  340. roles = load('Role')
  341. # create agents
  342. users = load('User')
  343. user(users, groups, roles, queues)
  344. # create organizations
  345. organizations = load('Customer')
  346. organization(organizations)
  347. # get changed tickets
  348. ticket_diff
  349. end
  350. def self.ticket_diff
  351. count = 0
  352. run = true
  353. steps = 20
  354. while run
  355. count += steps
  356. log 'loading... diff ...'
  357. records = load( 'Ticket', steps, count - steps, 1 )
  358. if !records || !records[0]
  359. log '... no more work.'
  360. run = false
  361. next
  362. end
  363. _ticket_result(records)
  364. end
  365. end
  366. def self._ticket_result(result, _thread = '-')
  367. map = {
  368. Ticket: {
  369. Changed: :updated_at,
  370. Created: :created_at,
  371. CreateBy: :created_by_id,
  372. TicketNumber: :number,
  373. QueueID: :group_id,
  374. StateID: :state_id,
  375. PriorityID: :priority_id,
  376. Owner: :owner,
  377. CustomerUserID: :customer,
  378. Title: :title,
  379. TicketID: :id,
  380. FirstResponse: :first_response,
  381. #FirstResponseTimeDestinationDate: :first_response_escal_date,
  382. #FirstResponseInMin: :first_response_in_min,
  383. #FirstResponseDiffInMin: :first_response_diff_in_min,
  384. Closed: :close_time,
  385. #SoltutionTimeDestinationDate: :close_time_escal_date,
  386. #CloseTimeInMin: :close_time_in_min,
  387. #CloseTimeDiffInMin: :close_time_diff_in_min,
  388. },
  389. Article: {
  390. SenderType: :sender,
  391. ArticleType: :type,
  392. TicketID: :ticket_id,
  393. ArticleID: :id,
  394. Body: :body,
  395. From: :from,
  396. To: :to,
  397. Cc: :cc,
  398. Subject: :subject,
  399. InReplyTo: :in_reply_to,
  400. MessageID: :message_id,
  401. #ReplyTo: :reply_to,
  402. References: :references,
  403. Changed: :updated_at,
  404. Created: :created_at,
  405. ChangedBy: :updated_by_id,
  406. CreatedBy: :created_by_id,
  407. },
  408. }
  409. result.each {|record|
  410. # cleanup values
  411. _cleanup(record)
  412. _utf8_encode(record)
  413. ticket_new = {
  414. title: '',
  415. created_by_id: 1,
  416. updated_by_id: 1,
  417. }
  418. map[:Ticket].each { |key, value|
  419. next if !record.key?(key.to_s)
  420. ticket_new[value] = record[key.to_s]
  421. }
  422. # find owner
  423. if ticket_new[:owner]
  424. user = User.lookup( login: ticket_new[:owner].downcase )
  425. if user
  426. ticket_new[:owner_id] = user.id
  427. else
  428. ticket_new[:owner_id] = 1
  429. end
  430. ticket_new.delete(:owner)
  431. end
  432. # find customer
  433. if ticket_new[:customer]
  434. user = User.lookup( login: ticket_new[:customer].downcase )
  435. if user
  436. ticket_new[:customer_id] = user.id
  437. else
  438. ticket_new[:customer_id] = 1
  439. end
  440. ticket_new.delete(:customer)
  441. else
  442. ticket_new[:customer_id] = 1
  443. end
  444. # update or create ticket
  445. ticket_old = Ticket.find_by(id: ticket_new[:id])
  446. if ticket_old
  447. log "update Ticket.find(#{ticket_new[:id]})"
  448. ticket_old.update_attributes(ticket_new)
  449. else
  450. log "add Ticket.find(#{ticket_new[:id]})"
  451. begin
  452. ticket = Ticket.new(ticket_new)
  453. ticket.id = ticket_new[:id]
  454. ticket.save
  455. rescue ActiveRecord::RecordNotUnique
  456. log "Ticket #{ticket_new[:id]} is handled by another thead, skipping."
  457. next
  458. end
  459. end
  460. # utf8 encode
  461. record['Articles'].each { |article|
  462. _utf8_encode(article)
  463. }
  464. # lookup customers to create first
  465. record['Articles'].each { |article|
  466. _article_based_customers(article)
  467. }
  468. record['Articles'].each do |article|
  469. retries = 3
  470. begin
  471. ActiveRecord::Base.transaction do
  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. begin
  523. article_object = Ticket::Article.new(article_new)
  524. article_object.id = article_new[:id]
  525. article_object.save
  526. rescue ActiveRecord::RecordNotUnique
  527. log "Ticket #{ticket_new[:id]} (article #{article_new[:id]}) is handled by another thead, skipping."
  528. next
  529. end
  530. end
  531. next if !article['Attachments']
  532. next if article['Attachments'].empty?
  533. # TODO: refactor
  534. # check if there are attachments present
  535. if !article_object.attachments.empty?
  536. # skip attachments if count is equal
  537. next if article_object.attachments.count == article['Attachments'].count
  538. # if the count differs delete all so we
  539. # can have a fresh start
  540. article_object.attachments.each(&:delete)
  541. end
  542. # import article attachments
  543. article['Attachments'].each { |attachment|
  544. filename = Base64.decode64(attachment['Filename'])
  545. Store.add(
  546. object: 'Ticket::Article',
  547. o_id: article_object.id,
  548. filename: filename,
  549. data: Base64.decode64(attachment['Content']),
  550. preferences: {
  551. 'Mime-Type' => attachment['ContentType'],
  552. 'Content-ID' => attachment['ContentID'],
  553. 'content-alternative' => attachment['ContentAlternative'],
  554. },
  555. created_by_id: 1,
  556. )
  557. }
  558. end
  559. rescue ActiveRecord::RecordNotUnique => e
  560. log "Ticket #{ticket_new[:id]} - RecordNotUnique: #{e}"
  561. sleep rand 3
  562. retry if !(retries -= 1).zero?
  563. raise
  564. end
  565. end
  566. #puts "HS: #{record['History'].inspect}"
  567. record['History'].each { |history|
  568. begin
  569. if history['HistoryType'] == 'NewTicket'
  570. History.add(
  571. id: history['HistoryID'],
  572. o_id: history['TicketID'],
  573. history_type: 'created',
  574. history_object: 'Ticket',
  575. created_at: history['CreateTime'],
  576. created_by_id: history['CreateBy']
  577. )
  578. elsif history['HistoryType'] == 'StateUpdate'
  579. data = history['Name']
  580. # "%%new%%open%%"
  581. from = nil
  582. to = nil
  583. if data =~ /%%(.+?)%%(.+?)%%/
  584. from = $1
  585. to = $2
  586. state_from = Ticket::State.lookup( name: from )
  587. state_to = Ticket::State.lookup( name: to )
  588. if state_from
  589. from_id = state_from.id
  590. end
  591. if state_to
  592. to_id = state_to.id
  593. end
  594. end
  595. History.add(
  596. id: history['HistoryID'],
  597. o_id: history['TicketID'],
  598. history_type: 'updated',
  599. history_object: 'Ticket',
  600. history_attribute: 'state',
  601. value_from: from,
  602. id_from: from_id,
  603. value_to: to,
  604. id_to: to_id,
  605. created_at: history['CreateTime'],
  606. created_by_id: history['CreateBy']
  607. )
  608. elsif history['HistoryType'] == 'Move'
  609. data = history['Name']
  610. # "%%Queue1%%5%%Postmaster%%1"
  611. from = nil
  612. to = nil
  613. if data =~ /%%(.+?)%%(.+?)%%(.+?)%%(.+?)$/
  614. from = $1
  615. from_id = $2
  616. to = $3
  617. to_id = $4
  618. end
  619. History.add(
  620. id: history['HistoryID'],
  621. o_id: history['TicketID'],
  622. history_type: 'updated',
  623. history_object: 'Ticket',
  624. history_attribute: 'group',
  625. value_from: from,
  626. value_to: to,
  627. id_from: from_id,
  628. id_to: to_id,
  629. created_at: history['CreateTime'],
  630. created_by_id: history['CreateBy']
  631. )
  632. elsif history['HistoryType'] == 'PriorityUpdate'
  633. data = history['Name']
  634. # "%%3 normal%%3%%5 very high%%5"
  635. from = nil
  636. to = nil
  637. if data =~ /%%(.+?)%%(.+?)%%(.+?)%%(.+?)$/
  638. from = $1
  639. from_id = $2
  640. to = $3
  641. to_id = $4
  642. end
  643. History.add(
  644. id: history['HistoryID'],
  645. o_id: history['TicketID'],
  646. history_type: 'updated',
  647. history_object: 'Ticket',
  648. history_attribute: 'priority',
  649. value_from: from,
  650. value_to: to,
  651. id_from: from_id,
  652. id_to: to_id,
  653. created_at: history['CreateTime'],
  654. created_by_id: history['CreateBy']
  655. )
  656. elsif history['ArticleID'] && !history['ArticleID'].to_i.zero?
  657. History.add(
  658. id: history['HistoryID'],
  659. o_id: history['ArticleID'],
  660. history_type: 'created',
  661. history_object: 'Ticket::Article',
  662. related_o_id: history['TicketID'],
  663. related_history_object: 'Ticket',
  664. created_at: history['CreateTime'],
  665. created_by_id: history['CreateBy']
  666. )
  667. end
  668. rescue ActiveRecord::RecordNotUnique
  669. log "Ticket #{ticket_new[:id]} (history #{history['HistoryID']}) is handled by another thead, skipping."
  670. next
  671. end
  672. }
  673. }
  674. end
  675. # sync ticket states
  676. def self.state(records)
  677. map = {
  678. ChangeTime: :updated_at,
  679. CreateTime: :created_at,
  680. CreateBy: :created_by_id,
  681. ChangeBy: :updated_by_id,
  682. Name: :name,
  683. ID: :id,
  684. ValidID: :active,
  685. Comment: :note,
  686. }
  687. # rename states to handle not uniq issues
  688. Ticket::State.all.each {|state|
  689. state.name = state.name + '_tmp'
  690. state.save
  691. }
  692. records.each { |state|
  693. _set_valid(state)
  694. # get new attributes
  695. state_new = {
  696. created_by_id: 1,
  697. updated_by_id: 1,
  698. }
  699. map.each { |key, value|
  700. next if !state.key?(key.to_s)
  701. state_new[value] = state[key.to_s]
  702. }
  703. # check if state already exists
  704. state_old = Ticket::State.where( id: state_new[:id] ).first
  705. # set state types
  706. if state['TypeName'] == 'pending auto'
  707. state['TypeName'] = 'pending action'
  708. end
  709. state_type = Ticket::StateType.where( name: state['TypeName'] ).first
  710. state_new[:state_type_id] = state_type.id
  711. if state_old
  712. state_old.update_attributes(state_new)
  713. else
  714. state = Ticket::State.new(state_new)
  715. state.id = state_new[:id]
  716. state.save
  717. end
  718. }
  719. end
  720. # sync ticket priorities
  721. def self.priority(records)
  722. map = {
  723. ChangeTime: :updated_at,
  724. CreateTime: :created_at,
  725. CreateBy: :created_by_id,
  726. ChangeBy: :updated_by_id,
  727. Name: :name,
  728. ID: :id,
  729. ValidID: :active,
  730. Comment: :note,
  731. }
  732. records.each { |priority|
  733. _set_valid(priority)
  734. # get new attributes
  735. priority_new = {
  736. created_by_id: 1,
  737. updated_by_id: 1,
  738. }
  739. map.each { |key, value|
  740. next if !priority.key?(key.to_s)
  741. priority_new[value] = priority[key.to_s]
  742. }
  743. # check if state already exists
  744. priority_old = Ticket::Priority.where( id: priority_new[:id] ).first
  745. # set state types
  746. if priority_old
  747. priority_old.update_attributes(priority_new)
  748. else
  749. priority = Ticket::Priority.new(priority_new)
  750. priority.id = priority_new[:id]
  751. priority.save
  752. end
  753. }
  754. end
  755. # sync ticket groups / queues
  756. def self.ticket_group(records)
  757. map = {
  758. ChangeTime: :updated_at,
  759. CreateTime: :created_at,
  760. CreateBy: :created_by_id,
  761. ChangeBy: :updated_by_id,
  762. Name: :name,
  763. QueueID: :id,
  764. ValidID: :active,
  765. Comment: :note,
  766. }
  767. records.each { |group|
  768. _set_valid(group)
  769. # get new attributes
  770. group_new = {
  771. created_by_id: 1,
  772. updated_by_id: 1,
  773. }
  774. map.each { |key, value|
  775. next if !group.key?(key.to_s)
  776. group_new[value] = group[key.to_s]
  777. }
  778. # check if state already exists
  779. group_old = Group.where( id: group_new[:id] ).first
  780. # set state types
  781. if group_old
  782. group_old.update_attributes(group_new)
  783. else
  784. group = Group.new(group_new)
  785. group.id = group_new[:id]
  786. group.save
  787. end
  788. }
  789. end
  790. # sync agents
  791. def self.user(records, groups, roles, queues)
  792. map = {
  793. ChangeTime: :updated_at,
  794. CreateTime: :created_at,
  795. CreateBy: :created_by_id,
  796. ChangeBy: :updated_by_id,
  797. UserID: :id,
  798. ValidID: :active,
  799. Comment: :note,
  800. UserEmail: :email,
  801. UserFirstname: :firstname,
  802. UserLastname: :lastname,
  803. UserLogin: :login,
  804. UserPw: :password,
  805. }
  806. records.each { |user|
  807. _set_valid(user)
  808. # get roles
  809. role_ids = get_roles_ids(user, groups, roles, queues)
  810. # get groups
  811. group_ids = get_queue_ids(user, groups, roles, queues)
  812. # get new attributes
  813. user_new = {
  814. created_by_id: 1,
  815. updated_by_id: 1,
  816. source: 'OTRS Import',
  817. role_ids: role_ids,
  818. group_ids: group_ids,
  819. }
  820. map.each { |key, value|
  821. next if !user.key?(key.to_s)
  822. user_new[value] = user[key.to_s]
  823. }
  824. # set pw
  825. if user_new[:password]
  826. user_new[:password] = "{sha2}#{user_new[:password]}"
  827. end
  828. # check if agent already exists
  829. user_old = User.where( id: user_new[:id] ).first
  830. # check if login is already used
  831. login_in_use = User.where( "login = ? AND id != #{user_new[:id]}", user_new[:login].downcase ).count
  832. if login_in_use > 0
  833. user_new[:login] = "#{user_new[:login]}_#{user_new[:id]}"
  834. end
  835. # create / update agent
  836. if user_old
  837. log "update User.find(#{user_old[:id]})"
  838. # only update roles if different (reduce sql statements)
  839. if user_old.role_ids == user_new[:role_ids]
  840. user_new.delete( :role_ids )
  841. end
  842. user_old.update_attributes(user_new)
  843. else
  844. log "add User.find(#{user_new[:id]})"
  845. user = User.new(user_new)
  846. user.id = user_new[:id]
  847. user.save
  848. end
  849. }
  850. end
  851. def self.get_queue_ids(user, _groups, _roles, queues)
  852. queue_ids = []
  853. # lookup by groups
  854. user['GroupIDs'].each {|group_id, permissions|
  855. queues.each {|queue_lookup|
  856. next if queue_lookup['GroupID'] != group_id
  857. next if !permissions
  858. next if !permissions.include?('rw')
  859. queue_ids.push queue_lookup['QueueID']
  860. }
  861. }
  862. # lookup by roles
  863. # roles of user
  864. # groups of roles
  865. # queues of group
  866. queue_ids
  867. end
  868. def self.get_roles_ids(user, groups, roles, _queues)
  869. local_roles = ['Agent']
  870. local_role_ids = []
  871. # apply group permissions
  872. user['GroupIDs'].each {|group_id, permissions|
  873. groups.each {|group_lookup|
  874. next if group_id != group_lookup['ID']
  875. next if !permissions
  876. if group_lookup['Name'] == 'admin' && permissions.include?('rw')
  877. local_roles.push 'Admin'
  878. end
  879. next if group_lookup['Name'] !~ /^(stats|report)/
  880. next if !( permissions.include?('ro') || permissions.include?('rw') )
  881. local_roles.push 'Report'
  882. }
  883. }
  884. # apply role permissions
  885. user['RoleIDs'].each {|role_id|
  886. # get groups of role
  887. roles.each {|role|
  888. next if role['ID'] != role_id
  889. # verify group names
  890. role['GroupIDs'].each {|group_id, permissions|
  891. groups.each {|group_lookup|
  892. next if group_id != group_lookup['ID']
  893. next if !permissions
  894. if group_lookup['Name'] == 'admin' && permissions.include?('rw')
  895. local_roles.push 'Admin'
  896. end
  897. next if group_lookup['Name'] !~ /^(stats|report)/
  898. next if !( permissions.include?('ro') || permissions.include?('rw') )
  899. local_roles.push 'Report'
  900. }
  901. }
  902. }
  903. }
  904. local_roles.each {|role|
  905. role_lookup = Role.lookup( name: role )
  906. next if !role_lookup
  907. local_role_ids.push role_lookup.id
  908. }
  909. local_role_ids
  910. end
  911. # sync customers
  912. def self.customer(records, organizations)
  913. map = {
  914. ChangeTime: :updated_at,
  915. CreateTime: :created_at,
  916. CreateBy: :created_by_id,
  917. ChangeBy: :updated_by_id,
  918. ValidID: :active,
  919. UserComment: :note,
  920. UserEmail: :email,
  921. UserFirstname: :firstname,
  922. UserLastname: :lastname,
  923. UserLogin: :login,
  924. UserPassword: :password,
  925. UserPhone: :phone,
  926. UserFax: :fax,
  927. UserMobile: :mobile,
  928. UserStreet: :street,
  929. UserZip: :zip,
  930. UserCity: :city,
  931. UserCountry: :country,
  932. }
  933. role_agent = Role.lookup( name: 'Agent' )
  934. role_customer = Role.lookup( name: 'Customer' )
  935. records.each { |user|
  936. _set_valid(user)
  937. # get new attributes
  938. user_new = {
  939. created_by_id: 1,
  940. updated_by_id: 1,
  941. source: 'OTRS Import',
  942. organization_id: get_organization_id(user, organizations),
  943. role_ids: [ role_customer.id ],
  944. }
  945. map.each { |key, value|
  946. next if !user.key?(key.to_s)
  947. user_new[value] = user[key.to_s]
  948. }
  949. # check if customer already exists
  950. user_old = User.where( login: user_new[:login].downcase ).first
  951. # create / update agent
  952. if user_old
  953. # do not update user if it is already agent
  954. if !user_old.role_ids.include?( role_agent.id )
  955. # only update roles if different (reduce sql statements)
  956. if user_old.role_ids == user_new[:role_ids]
  957. user_new.delete( :role_ids )
  958. end
  959. log "update User.find(#{user_old[:id]})"
  960. user_old.update_attributes(user_new)
  961. end
  962. else
  963. log "add User.find(#{user_new[:id]})"
  964. user = User.new(user_new)
  965. user.save
  966. end
  967. }
  968. end
  969. def self.get_organization_id(user, organizations)
  970. organization_id = nil
  971. if user['UserCustomerID']
  972. organizations.each {|organization|
  973. next if user['UserCustomerID'] != organization['CustomerID']
  974. organization = Organization.where(name: organization['CustomerCompanyName'] ).first
  975. organization_id = organization.id
  976. }
  977. end
  978. organization_id
  979. end
  980. # sync organizations
  981. def self.organization(records)
  982. map = {
  983. ChangeTime: :updated_at,
  984. CreateTime: :created_at,
  985. CreateBy: :created_by_id,
  986. ChangeBy: :updated_by_id,
  987. CustomerCompanyName: :name,
  988. ValidID: :active,
  989. CustomerCompanyComment: :note,
  990. }
  991. records.each { |organization|
  992. _set_valid(organization)
  993. # get new attributes
  994. organization_new = {
  995. created_by_id: 1,
  996. updated_by_id: 1,
  997. }
  998. map.each { |key, value|
  999. next if !organization.key?(key.to_s)
  1000. organization_new[value] = organization[key.to_s]
  1001. }
  1002. # check if state already exists
  1003. organization_old = Organization.where( name: organization_new[:name] ).first
  1004. # set state types
  1005. if organization_old
  1006. organization_old.update_attributes(organization_new)
  1007. else
  1008. organization = Organization.new(organization_new)
  1009. organization.id = organization_new[:id]
  1010. organization.save
  1011. end
  1012. }
  1013. end
  1014. # sync settings
  1015. def self.setting(records)
  1016. records.each { |setting|
  1017. # fqdn
  1018. if setting['Key'] == 'FQDN'
  1019. Setting.set( 'fqdn', setting['Value'] )
  1020. end
  1021. # http type
  1022. if setting['Key'] == 'HttpType'
  1023. Setting.set( 'http_type', setting['Value'] )
  1024. end
  1025. # system id
  1026. if setting['Key'] == 'SystemID'
  1027. Setting.set( 'system_id', setting['Value'] )
  1028. end
  1029. # organization
  1030. if setting['Key'] == 'Organization'
  1031. Setting.set( 'organization', setting['Value'] )
  1032. end
  1033. # sending emails
  1034. if setting['Key'] == 'SendmailModule'
  1035. # TODO
  1036. end
  1037. # number generater
  1038. if setting['Key'] == 'Ticket::NumberGenerator'
  1039. if setting['Value'] == 'Kernel::System::Ticket::Number::DateChecksum'
  1040. Setting.set( 'ticket_number', 'Ticket::Number::Date' )
  1041. Setting.set( 'ticket_number_date', { checksum: true } )
  1042. elsif setting['Value'] == 'Kernel::System::Ticket::Number::Date'
  1043. Setting.set( 'ticket_number', 'Ticket::Number::Date' )
  1044. Setting.set( 'ticket_number_date', { checksum: false } )
  1045. end
  1046. end
  1047. # ticket hook
  1048. if setting['Key'] == 'Ticket::Hook'
  1049. Setting.set( 'ticket_hook', setting['Value'] )
  1050. end
  1051. }
  1052. end
  1053. # log
  1054. def self.log(message)
  1055. thread_no = Thread.current[:thread_no] || '-'
  1056. Rails.logger.info "thread##{thread_no}: #{message}"
  1057. end
  1058. # set translate valid ids to active = true|false
  1059. def self._set_valid(record)
  1060. # map
  1061. if record['ValidID'].to_s == '3'
  1062. record['ValidID'] = false
  1063. elsif record['ValidID'].to_s == '2'
  1064. record['ValidID'] = false
  1065. elsif record['ValidID'].to_s == '1'
  1066. record['ValidID'] = true
  1067. elsif record['ValidID'].to_s == '0'
  1068. record['ValidID'] = false
  1069. # fallback
  1070. else
  1071. record['ValidID'] = true
  1072. end
  1073. end
  1074. # cleanup invalid values
  1075. def self._cleanup(record)
  1076. record.each {|key, value|
  1077. if value == '0000-00-00 00:00:00'
  1078. record[key] = nil
  1079. end
  1080. }
  1081. # fix OTRS 3.1 bug, no close time if ticket is created
  1082. if record['StateType'] == 'closed' && ( !record['Closed'] || record['Closed'].empty? )
  1083. record['Closed'] = record['Created']
  1084. end
  1085. end
  1086. # utf8 convert
  1087. def self._utf8_encode(data)
  1088. data.each { |key, value|
  1089. next if !value
  1090. next if value.class != String
  1091. data[key] = Encode.conv( 'utf8', value )
  1092. }
  1093. end
  1094. # create customers for article
  1095. def self._article_based_customers(article)
  1096. # create customer/sender if needed
  1097. return if article['sender'] != 'customer'
  1098. return if article['created_by_id'].to_i != 1
  1099. return if article['from'].empty?
  1100. email = nil
  1101. begin
  1102. email = Mail::Address.new( article['from'] ).address
  1103. rescue
  1104. email = article['from']
  1105. if article['from'] =~ /<(.+?)>/
  1106. email = $1
  1107. end
  1108. end
  1109. user = User.where( email: email.downcase ).first
  1110. if !user
  1111. user = User.where( login: email.downcase ).first
  1112. end
  1113. if !user
  1114. begin
  1115. display_name = Mail::Address.new( article['from'] ).display_name ||
  1116. ( Mail::Address.new( article['from'] ).comments && Mail::Address.new( article['from'] ).comments[0] )
  1117. rescue
  1118. display_name = article['from']
  1119. end
  1120. # do extra decoding because we needed to use field.value
  1121. display_name = Mail::Field.new( 'X-From', display_name ).to_s
  1122. roles = Role.lookup( name: 'Customer' )
  1123. begin
  1124. user = User.create(
  1125. login: email,
  1126. firstname: display_name,
  1127. lastname: '',
  1128. email: email,
  1129. password: '',
  1130. active: true,
  1131. role_ids: [roles.id],
  1132. updated_by_id: 1,
  1133. created_by_id: 1,
  1134. )
  1135. rescue ActiveRecord::RecordNotUnique
  1136. log "User #{email} was handled by another thread, taking this."
  1137. user = User.find_by( login: email.downcase )
  1138. if !user
  1139. log "User #{email} wasn't created sleep and retry."
  1140. sleep rand 3
  1141. retry
  1142. end
  1143. end
  1144. end
  1145. article['created_by_id'] = user.id
  1146. true
  1147. end
  1148. end