zendesk.rb 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. require 'base64'
  2. require 'zendesk_api'
  3. module Import
  4. end
  5. module Import::Zendesk
  6. module_function
  7. def start
  8. Rails.logger.info 'Start import...'
  9. # check if system is in import mode
  10. if !Setting.get('import_mode')
  11. raise 'System is not in import mode!'
  12. end
  13. initialize_client
  14. import_fields
  15. # TODO
  16. # import_oauth
  17. # import_twitter_channel
  18. import_groups
  19. import_organizations
  20. import_users
  21. import_tickets
  22. # TODO
  23. # import_sla_policies
  24. # import_macros
  25. # import_schedules
  26. # import_views
  27. # import_automations
  28. Setting.set( 'system_init_done', true )
  29. Setting.set( 'import_mode', false )
  30. true
  31. end
  32. =begin
  33. start import in background
  34. Import::Zendesk.start_bg
  35. =end
  36. def start_bg
  37. Setting.reload
  38. Import::Zendesk.connection_test
  39. # get statistic before starting import
  40. statistic
  41. # start thread to observe current state
  42. status_update_thread = Thread.new {
  43. loop do
  44. result = {
  45. data: current_state,
  46. result: 'in_progress',
  47. }
  48. Cache.write('import:state', result, expires_in: 10.minutes)
  49. sleep 8
  50. end
  51. }
  52. sleep 2
  53. # start import data
  54. begin
  55. Import::Zendesk.start
  56. rescue => e
  57. status_update_thread.exit
  58. status_update_thread.join
  59. Rails.logger.error e.message
  60. Rails.logger.error e.backtrace.inspect
  61. result = {
  62. message: e.message,
  63. result: 'error',
  64. }
  65. Cache.write('import:state', result, expires_in: 10.hours)
  66. return false
  67. end
  68. sleep 16 # wait until new finished import state is on client
  69. status_update_thread.exit
  70. status_update_thread.join
  71. result = {
  72. result: 'import_done',
  73. }
  74. Cache.write('import:state', result, expires_in: 10.hours)
  75. Setting.set('system_init_done', true)
  76. Setting.set('import_mode', false)
  77. end
  78. =begin
  79. get import state from background process
  80. result = Import::Zendesk.status_bg
  81. =end
  82. def status_bg
  83. state = Cache.get('import:state')
  84. return state if state
  85. {
  86. message: 'not running',
  87. }
  88. end
  89. =begin
  90. start get request to backend to check connection
  91. result = connection_test
  92. return
  93. true | false
  94. =end
  95. def connection_test
  96. initialize_client
  97. return true if @client.users.first
  98. false
  99. end
  100. def statistic
  101. # check cache
  102. cache = Cache.get('import_zendesk_stats')
  103. if cache
  104. return cache
  105. end
  106. initialize_client
  107. # retrive statistic
  108. result = {
  109. 'Tickets' => 0,
  110. 'TicketFields' => 0,
  111. 'UserFields' => 0,
  112. 'OrganizationFields' => 0,
  113. 'Groups' => 0,
  114. 'Organizations' => 0,
  115. 'Users' => 0,
  116. 'GroupMemberships' => 0,
  117. 'Macros' => 0,
  118. 'Views' => 0,
  119. 'Automations' => 0,
  120. }
  121. result.each { |object, _score|
  122. result[ object ] = @client.send( object.underscore.to_sym ).count!
  123. }
  124. if result
  125. Cache.write('import_zendesk_stats', result)
  126. end
  127. result
  128. end
  129. =begin
  130. return current import state
  131. result = current_state
  132. return
  133. {
  134. Group: {
  135. total: 1234,
  136. done: 13,
  137. },
  138. Organization: {
  139. total: 1234,
  140. done: 13,
  141. },
  142. User: {
  143. total: 1234,
  144. done: 13,
  145. },
  146. Ticket: {
  147. total: 1234,
  148. done: 13,
  149. },
  150. }
  151. =end
  152. def current_state
  153. data = statistic
  154. {
  155. Group: {
  156. done: Group.count,
  157. total: data['Groups'] || 0,
  158. },
  159. Organization: {
  160. done: Organization.count,
  161. total: data['Organizations'] || 0,
  162. },
  163. User: {
  164. done: User.count,
  165. total: data['Users'] || 0,
  166. },
  167. Ticket: {
  168. done: Ticket.count,
  169. total: data['Tickets'] || 0,
  170. },
  171. }
  172. end
  173. def initialize_client
  174. @client = ZendeskAPI::Client.new do |config|
  175. config.url = Setting.get('import_zendesk_endpoint')
  176. # Basic / Token Authentication
  177. config.username = Setting.get('import_zendesk_endpoint_username')
  178. config.token = Setting.get('import_zendesk_endpoint_key')
  179. # when hitting the rate limit, sleep automatically,
  180. # then retry the request.
  181. config.retry = true
  182. end
  183. end
  184. def mapping_state(zendesk_state)
  185. mapping = {
  186. 'pending' => 'pending reminder',
  187. 'solved' => 'closed',
  188. }
  189. return zendesk_state if !mapping[zendesk_state]
  190. mapping[zendesk_state]
  191. end
  192. def mapping_priority(zendesk_priority)
  193. mapping = {
  194. 'low' => '1 low',
  195. nil => '2 normal',
  196. 'normal' => '2 normal',
  197. 'high' => '3 high',
  198. 'urgent' => '3 high',
  199. }
  200. mapping[zendesk_priority]
  201. end
  202. # NOT IMPLEMENTED YET
  203. def mapping_type(zendesk_type)
  204. mapping = {
  205. nil => '',
  206. 'question' => '',
  207. 'incident' => '',
  208. 'problem' => '',
  209. 'task' => '',
  210. }
  211. return zendesk_type if !mapping[zendesk_type]
  212. mapping[zendesk_type]
  213. end
  214. def mapping_ticket_field(zendesk_field)
  215. mapping = {
  216. 'subject' => 'title',
  217. 'description' => 'note',
  218. 'status' => 'state_id',
  219. 'tickettype' => 'type',
  220. 'priority' => 'priority_id',
  221. 'group' => 'group_id',
  222. 'assignee' => 'owner_id',
  223. }
  224. return zendesk_field if !mapping[zendesk_field]
  225. mapping[zendesk_field]
  226. end
  227. # FILTER:
  228. # TODO:
  229. # https://developer.zendesk.com/rest_api/docs/core/views#conditions-reference
  230. def mapping_filter(zendesk_filter)
  231. end
  232. # Ticket Fields
  233. # User Fields
  234. # Organization Fields
  235. # TODO:
  236. # https://developer.zendesk.com/rest_api/docs/core/ticket_fields
  237. # https://developer.zendesk.com/rest_api/docs/core/user_fields
  238. # https://developer.zendesk.com/rest_api/docs/core/organization_fields
  239. def import_fields
  240. %w(Ticket User Organization).each { |local_object|
  241. local_fields = local_object.constantize.column_names
  242. @client.send("#{local_object.downcase}_fields").all! { |zendesk_object_field|
  243. if local_object == 'Ticket'
  244. mapped_object_field = method("mapping_#{local_object.downcase}_field").call( zendesk_object_field.type )
  245. next if local_fields.include?( mapped_object_field )
  246. end
  247. import_field(local_object, zendesk_object_field)
  248. }
  249. }
  250. end
  251. def import_field(local_object, zendesk_field)
  252. name = ''
  253. name = if local_object == 'Ticket'
  254. zendesk_field.title
  255. else
  256. zendesk_field['key'] # TODO: y?!
  257. end
  258. @zendesk_field_mapping ||= {}
  259. @zendesk_field_mapping[ zendesk_field.id ] = name
  260. data_type = zendesk_field.type
  261. data_option = {
  262. null: !zendesk_field.required,
  263. note: zendesk_field.description,
  264. }
  265. if zendesk_field.type == 'date'
  266. data_option = {
  267. future: true,
  268. past: true,
  269. diff: 0,
  270. }.merge(data_option)
  271. elsif zendesk_field.type == 'checkbox'
  272. data_type = 'boolean'
  273. data_option = {
  274. default: false,
  275. options: {
  276. true => 'yes',
  277. false => 'no',
  278. },
  279. }.merge(data_option)
  280. elsif zendesk_field.type == 'regexp'
  281. data_type = 'input'
  282. data_option = {
  283. type: 'text',
  284. maxlength: 255,
  285. regex: zendesk_field.regexp_for_validation,
  286. }.merge(data_option)
  287. elsif zendesk_field.type == 'decimal'
  288. data_type = 'input'
  289. data_option = {
  290. type: 'text',
  291. maxlength: 255,
  292. }.merge(data_option)
  293. elsif zendesk_field.type == 'integer'
  294. data_type = 'integer'
  295. data_option = {
  296. min: 0,
  297. max: 999_999_999,
  298. }.merge(data_option)
  299. elsif zendesk_field.type == 'text'
  300. data_type = 'input'
  301. data_option = {
  302. type: zendesk_field.type,
  303. maxlength: 255,
  304. }.merge(data_option)
  305. elsif zendesk_field.type == 'textarea'
  306. data_type = 'input'
  307. data_option = {
  308. type: zendesk_field.type,
  309. maxlength: 255,
  310. }.merge(data_option)
  311. elsif zendesk_field.type == 'tagger' || zendesk_field.type == 'dropdown'
  312. # \"custom_field_options\"=>[{\"id\"=>28353445
  313. # \"name\"=>\"Another Value\"
  314. # \"raw_name\"=>\"Another Value\"
  315. # \"value\"=>\"anotherkey\"}
  316. # {\"id\"=>28353425
  317. # \"name\"=>\"Value 1\"
  318. # \"raw_name\"=>\"Value 1\"
  319. # \"value\"=>\"key1\"}
  320. # {\"id\"=>28353435
  321. # \"name\"=>\"Value 2\"
  322. # \"raw_name\"=>\"Value 2\"
  323. # \"value\"=>\"key2\"}]}>
  324. # "
  325. options = {}
  326. @zendesk_ticket_field_value_mapping ||= {}
  327. zendesk_field.custom_field_options.each { |entry|
  328. if local_object == 'Ticket'
  329. @zendesk_ticket_field_value_mapping[ name ] ||= {}
  330. @zendesk_ticket_field_value_mapping[ name ][ entry['id'] ] = entry['value']
  331. end
  332. options[ entry['value'] ] = entry['name']
  333. }
  334. data_type = 'select'
  335. data_option = {
  336. default: '',
  337. options: options,
  338. }.merge(data_option)
  339. end
  340. screens = {
  341. view: {
  342. '-all-' => {
  343. shown: true,
  344. },
  345. }
  346. }
  347. if zendesk_field.visible_in_portal || !zendesk_field.required_in_portal
  348. screens = {
  349. edit: {
  350. Customer: {
  351. shown: zendesk_field.visible_in_portal,
  352. null: !zendesk_field.required_in_portal,
  353. },
  354. }.merge(screens)
  355. }
  356. end
  357. name.gsub!(/\s/, '_')
  358. ObjectManager::Attribute.add(
  359. object: local_object,
  360. name: name,
  361. display: zendesk_field.title,
  362. data_type: data_type,
  363. data_option: data_option,
  364. editable: !zendesk_field.removable,
  365. active: zendesk_field.active,
  366. screens: screens,
  367. position: zendesk_field.position,
  368. created_by_id: 1,
  369. updated_by_id: 1,
  370. )
  371. ObjectManager::Attribute.migration_execute(false)
  372. end
  373. # OAuth
  374. # TODO:
  375. # https://developer.zendesk.com/rest_api/docs/core/oauth_tokens
  376. # https://developer.zendesk.com/rest_api/docs/core/oauth_clients
  377. def import_oauth
  378. end
  379. # Twitter
  380. # TODO:
  381. # https://developer.zendesk.com/rest_api/docs/core/twitter_channel
  382. def import_twitter
  383. end
  384. # Groups
  385. # https://developer.zendesk.com/rest_api/docs/core/groups
  386. def import_groups
  387. @zendesk_group_mapping = {}
  388. @client.groups.all! { |zendesk_group|
  389. local_group = Group.create_if_not_exists(
  390. name: zendesk_group.name,
  391. active: !zendesk_group.deleted,
  392. updated_by_id: 1,
  393. created_by_id: 1
  394. )
  395. @zendesk_group_mapping[ zendesk_group.id ] = local_group.id
  396. }
  397. end
  398. # Organizations
  399. # https://developer.zendesk.com/rest_api/docs/core/organizations
  400. def import_organizations
  401. @zendesk_organization_mapping = {}
  402. @client.organizations.each { |zendesk_organization|
  403. custom_fields = get_fields(zendesk_organization.organization_fields)
  404. local_organization_fields = {
  405. name: zendesk_organization.name,
  406. note: zendesk_organization.note,
  407. shared: zendesk_organization.shared_tickets,
  408. # shared: zendesk_organization.shared_comments, # TODO, not yet implemented
  409. # }.merge(zendesk_organization.organization_fields) # TODO
  410. updated_by_id: 1,
  411. created_by_id: 1
  412. }.merge(custom_fields)
  413. local_organization = Organization.create_if_not_exists(local_organization_fields)
  414. @zendesk_organization_mapping[ zendesk_organization.id ] = local_organization.id
  415. }
  416. end
  417. # Users
  418. # https://developer.zendesk.com/rest_api/docs/core/users
  419. def import_users
  420. import_group_memberships
  421. import_custom_roles
  422. @zendesk_user_mapping = {}
  423. role_admin = Role.lookup(name: 'Admin')
  424. role_agent = Role.lookup(name: 'Agent')
  425. role_customer = Role.lookup(name: 'Customer')
  426. @client.users.all! { |zendesk_user|
  427. custom_fields = get_fields(zendesk_user.user_fields)
  428. local_user_fields = {
  429. login: zendesk_user.id.to_s, # Zendesk users may have no other identifier than the ID, e.g. twitter users
  430. firstname: zendesk_user.name,
  431. email: zendesk_user.email,
  432. phone: zendesk_user.phone,
  433. password: '',
  434. active: !zendesk_user.suspended,
  435. groups: [],
  436. roles: [],
  437. note: zendesk_user.notes,
  438. verified: zendesk_user.verified,
  439. organization_id: @zendesk_organization_mapping[ zendesk_user.organization_id ],
  440. last_login: zendesk_user.last_login_at,
  441. updated_by_id: 1,
  442. created_by_id: 1
  443. }.merge(custom_fields)
  444. if @zendesk_user_group_mapping[ zendesk_user.id ]
  445. @zendesk_user_group_mapping[ zendesk_user.id ].each { |zendesk_group_id|
  446. local_group_id = @zendesk_group_mapping[ zendesk_group_id ]
  447. next if !local_group_id
  448. group = Group.find( local_group_id )
  449. local_user_fields[:groups].push group
  450. }
  451. end
  452. if zendesk_user.role.name == 'end-user'
  453. local_user_fields[:roles].push role_customer
  454. elsif zendesk_user.role.name == 'agent'
  455. local_user_fields[:roles].push role_agent
  456. if !zendesk_user.restricted_agent
  457. local_user_fields[:roles].push role_admin
  458. end
  459. elsif zendesk_user.role.name == 'admin'
  460. local_user_fields[:roles].push role_agent
  461. local_user_fields[:roles].push role_admin
  462. end
  463. if zendesk_user.photo && zendesk_user.photo.content_url
  464. local_user_fields[:image_source] = zendesk_user.photo.content_url
  465. end
  466. # TODO
  467. # local_user_fields = local_user_fields.merge( user.user_fields )
  468. # TODO
  469. # user.custom_role_id (Enterprise only)
  470. local_user = User.create_or_update( local_user_fields )
  471. @zendesk_user_mapping[ zendesk_user.id ] = local_user.id
  472. }
  473. end
  474. # Group Memberships
  475. # TODO:
  476. # https://developer.zendesk.com/rest_api/docs/core/group_memberships
  477. def import_group_memberships
  478. @zendesk_user_group_mapping = {}
  479. @client.group_memberships.all! { |zendesk_group_membership|
  480. @zendesk_user_group_mapping[ zendesk_group_membership.user_id ] ||= []
  481. @zendesk_user_group_mapping[ zendesk_group_membership.user_id ].push( zendesk_group_membership.group_id )
  482. }
  483. end
  484. # Custom Roles (Enterprise only)
  485. # TODO:
  486. # https://developer.zendesk.com/rest_api/docs/core/custom_roles
  487. def import_custom_roles
  488. end
  489. # Tickets
  490. # https://developer.zendesk.com/rest_api/docs/core/tickets
  491. # https://developer.zendesk.com/rest_api/docs/core/ticket_comments#ticket-comments
  492. # https://developer.zendesk.com/rest_api/docs/core/ticket_audits#the-via-object
  493. # https://developer.zendesk.com/rest_api/docs/help_center/article_attachments
  494. # https://developer.zendesk.com/rest_api/docs/core/ticket_audits # v2
  495. def import_tickets
  496. article_sender_customer = Ticket::Article::Sender.lookup(name: 'Customer')
  497. article_sender_agent = Ticket::Article::Sender.lookup(name: 'Agent')
  498. article_sender_system = Ticket::Article::Sender.lookup(name: 'System')
  499. article_type_web = Ticket::Article::Type.lookup(name: 'web')
  500. article_type_note = Ticket::Article::Type.lookup(name: 'note')
  501. article_type_email = Ticket::Article::Type.lookup(name: 'email')
  502. article_type_twitter_status = Ticket::Article::Type.lookup(name: 'twitter status')
  503. article_type_twitter_dm = Ticket::Article::Type.lookup(name: 'twitter direct-message')
  504. article_type_facebook_feed_post = Ticket::Article::Type.lookup(name: 'facebook feed post')
  505. article_type_facebook_feed_comment = Ticket::Article::Type.lookup(name: 'facebook feed comment')
  506. @client.tickets.all! { |zendesk_ticket|
  507. custom_fields = get_custom_fields(zendesk_ticket.custom_fields)
  508. local_ticket_fields = {
  509. id: zendesk_ticket.id,
  510. title: zendesk_ticket.subject,
  511. note: zendesk_ticket.description,
  512. group_id: @zendesk_group_mapping[ zendesk_ticket.group_id ] || 1,
  513. customer_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ] || 1,
  514. organization_id: @zendesk_organization_mapping[ zendesk_ticket.organization_id ],
  515. state: Ticket::State.lookup( name: mapping_state( zendesk_ticket.status ) ),
  516. priority: Ticket::Priority.lookup( name: mapping_priority( zendesk_ticket.priority ) ),
  517. pending_time: zendesk_ticket.due_at,
  518. updated_at: zendesk_ticket.updated_at,
  519. created_at: zendesk_ticket.created_at,
  520. updated_by_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ] || 1,
  521. created_by_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ] || 1,
  522. }.merge(custom_fields)
  523. ticket_author = User.find( @zendesk_user_mapping[ zendesk_ticket.requester_id ] || 1 )
  524. local_ticket_fields[:create_article_sender_id] = if ticket_author.role?('Customer')
  525. article_sender_customer.id
  526. elsif ticket_author.role?('Agent')
  527. article_sender_agent.id
  528. else
  529. article_sender_system.id
  530. end
  531. if zendesk_ticket.via.channel == 'web'
  532. local_ticket_fields[:create_article_type_id] = article_type_web.id
  533. elsif zendesk_ticket.via.channel == 'email'
  534. local_ticket_fields[:create_article_type_id] = article_type_email.id
  535. elsif zendesk_ticket.via.channel == 'sample_ticket'
  536. local_ticket_fields[:create_article_type_id] = article_type_note.id
  537. elsif zendesk_ticket.via.channel == 'twitter'
  538. local_ticket_fields[:create_article_type_id] = if zendesk_ticket.via.source.rel == 'mention'
  539. article_type_twitter_status.id
  540. else
  541. article_type_twitter_dm.id
  542. end
  543. elsif zendesk_ticket.via.channel == 'facebook'
  544. local_ticket_fields[:create_article_type_id] = if zendesk_ticket.via.source.rel == 'post'
  545. article_type_facebook_feed_post.id
  546. else
  547. article_type_facebook_feed_comment.id
  548. end
  549. end
  550. local_ticket = Ticket.find_by(id: local_ticket_fields[:id])
  551. if local_ticket
  552. local_ticket.update_attributes(local_ticket_fields)
  553. else
  554. local_ticket = Ticket.create(local_ticket_fields)
  555. _reset_pk('tickets')
  556. end
  557. zendesk_ticket_tags = []
  558. zendesk_ticket.tags.each { |tag|
  559. zendesk_ticket_tags.push(tag)
  560. }
  561. zendesk_ticket_tags.each { |tag|
  562. Tag.tag_add(
  563. object: 'Ticket',
  564. o_id: local_ticket.id,
  565. item: tag.id,
  566. created_by_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ] || 1,
  567. )
  568. }
  569. zendesk_ticket_articles = []
  570. zendesk_ticket.comments.each { |zendesk_article|
  571. zendesk_ticket_articles.push(zendesk_article)
  572. }
  573. zendesk_ticket_articles.each { |zendesk_article|
  574. local_article_fields = {
  575. ticket_id: local_ticket.id,
  576. body: zendesk_article.html_body,
  577. internal: !zendesk_article.public,
  578. message_id: zendesk_article.id,
  579. updated_by_id: @zendesk_user_mapping[ zendesk_article.author_id ] || 1,
  580. created_by_id: @zendesk_user_mapping[ zendesk_article.author_id ] || 1,
  581. }
  582. article_author = User.find( @zendesk_user_mapping[ zendesk_article.author_id ] || 1 )
  583. local_article_fields[:sender_id] = if article_author.role?('Customer')
  584. article_sender_customer.id
  585. elsif article_author.role?('Agent')
  586. article_sender_agent.id
  587. else
  588. article_sender_system.id
  589. end
  590. if zendesk_article.via.channel == 'web'
  591. local_article_fields[:type_id] = article_type_web.id
  592. elsif zendesk_article.via.channel == 'email'
  593. local_article_fields[:from] = zendesk_article.via.source.from.address
  594. local_article_fields[:to] = zendesk_article.via.source.to.address # Notice zendesk_article.via.from.original_recipients=[\"another@gmail.com\", \"support@example.zendesk.com\"]
  595. local_article_fields[:type_id] = article_type_email.id
  596. elsif zendesk_article.via.channel == 'sample_ticket'
  597. local_article_fields[:type_id] = article_type_note.id
  598. elsif zendesk_article.via.channel == 'twitter'
  599. local_article_fields[:type_id] = if zendesk_article.via.source.rel == 'mention'
  600. article_type_twitter_status.id
  601. else
  602. article_type_twitter_dm.id
  603. end
  604. elsif zendesk_article.via.channel == 'facebook'
  605. local_article_fields[:from] = zendesk_article.via.source.from.facebook_id
  606. local_article_fields[:to] = zendesk_article.via.source.to.facebook_id
  607. local_article_fields[:type_id] = if zendesk_article.via.source.rel == 'post'
  608. article_type_facebook_feed_post.id
  609. else
  610. article_type_facebook_feed_comment.id
  611. end
  612. end
  613. # create article
  614. local_article = Ticket::Article.find_by(message_id: local_article_fields[:message_id])
  615. if local_article
  616. local_article.update_attributes(local_article_fields)
  617. else
  618. local_article = Ticket::Article.create( local_article_fields )
  619. end
  620. zendesk_attachments = zendesk_article.attachments
  621. next if zendesk_attachments.size.zero?
  622. local_attachments = local_article.attachments
  623. zendesk_ticket_attachments = []
  624. zendesk_attachments.each { |zendesk_attachment|
  625. zendesk_ticket_attachments.push(zendesk_attachment)
  626. }
  627. zendesk_ticket_attachments.each { |zendesk_attachment|
  628. response = UserAgent.get(
  629. zendesk_attachment.content_url,
  630. {},
  631. {
  632. open_timeout: 10,
  633. read_timeout: 60,
  634. },
  635. )
  636. if !response.success?
  637. Rails.logger.error response.error
  638. next
  639. end
  640. local_attachment = Store.add(
  641. object: 'Ticket::Article',
  642. o_id: local_article.id,
  643. data: response.body,
  644. filename: zendesk_attachment.file_name,
  645. preferences: {
  646. 'Content-Type' => zendesk_attachment.content_type
  647. },
  648. created_by_id: 1
  649. )
  650. }
  651. }
  652. }
  653. end
  654. # SLA Policies
  655. # TODO:
  656. # https://github.com/zendesk/zendesk_api_client_rb/issues/271
  657. # https://developer.zendesk.com/rest_api/docs/core/sla_policies
  658. def import_sla_policies
  659. end
  660. # Macros
  661. # TODO:
  662. # https://developer.zendesk.com/rest_api/docs/core/macros
  663. def import_macros
  664. @client.macros.all! { |zendesk_macro|
  665. # TODO
  666. next if !zendesk_macro.active
  667. # "url"=>"https://example.zendesk.com/api/v2/macros/59511191.json"
  668. # "id"=>59511191
  669. # "title"=>"Herabstufen und informieren"
  670. # "active"=>true
  671. # "updated_at"=>2015-08-03 13:51:14 UTC
  672. # "created_at"=>2015-07-19 22:41:42 UTC
  673. # "restriction"=>nil
  674. # "actions"=>[
  675. # {
  676. # "field"=>"priority"
  677. # "value"=>"low"
  678. # }
  679. # {
  680. # "field"=>"comment_value"
  681. # "value"=>"Das Verkehrsaufkommen ist g....."
  682. # }
  683. # ]
  684. perform = {}
  685. zendesk_macro.actions.each { |action|
  686. # TODO: ID fields
  687. perform["ticket.#{action.field}"] = action.value
  688. }
  689. Macro.create_if_not_exists(
  690. name: zendesk_macro.title,
  691. perform: perform,
  692. note: '',
  693. active: zendesk_macro.active,
  694. )
  695. }
  696. end
  697. # Schedulers
  698. # TODO:
  699. # https://github.com/zendesk/zendesk_api_client_rb/issues/281
  700. # https://developer.zendesk.com/rest_api/docs/core/schedules
  701. def import_schedules
  702. end
  703. # Views
  704. # TODO:
  705. # https://developer.zendesk.com/rest_api/docs/core/views
  706. def import_views
  707. @client.views.all! { |zendesk_view|
  708. # "url" => "https://example.zendesk.com/api/v2/views/59511071.json"
  709. # "id" => 59511071
  710. # "title" => "Ihre Tickets"
  711. # "active" => true
  712. # "updated_at" => 2015-08-03 13:51:14 UTC
  713. # "created_at" => 2015-07-19 22:41:42 UTC
  714. # "restriction" => nil
  715. # "sla_id" => nil
  716. # "execution" => {
  717. # "group_by" => "status"
  718. # "group_order" => "asc"
  719. # "sort_by" => "score"
  720. # "sort_order" => "desc"
  721. # "group" => {
  722. # "id" => "status"
  723. # "title" => "Status"
  724. # "order" => "asc"
  725. # }
  726. # "sort" => {
  727. # "id" => "score"
  728. # "title" => "Score"
  729. # "order" => "desc"
  730. # }
  731. # "columns" => [
  732. # {
  733. # "id" => "score"
  734. # "title" => "Score"
  735. # }
  736. # {
  737. # "id" => "subject"
  738. # "title" => "Subject"
  739. # }
  740. # {
  741. # "id" => "requester"
  742. # "title" => "Requester"
  743. # }
  744. # {
  745. # "id" => "created"
  746. # "title" => "Requested"
  747. # }
  748. # {
  749. # "id" => "type"
  750. # "title" => "Type"
  751. # }
  752. # {
  753. # "id" => "priority"
  754. # "title" => "Priority"
  755. # }
  756. # ]
  757. # "fields" => [
  758. # {
  759. # "id" => "score"
  760. # "title" => "Score"
  761. # }
  762. # {
  763. # "id" => "subject"
  764. # "title" => "Subject"
  765. # }
  766. # {
  767. # "id" => "requester"
  768. # "title" => "Requester"
  769. # }
  770. # {
  771. # "id" => "created"
  772. # "title" => "Requested"
  773. # }
  774. # {
  775. # "id" => "type"
  776. # "title" => "Type"
  777. # }
  778. # {
  779. # "id" => "priority"
  780. # "title" => "Priority"
  781. # }
  782. # ]
  783. # "custom_fields" => []
  784. # }
  785. # "conditions" => {
  786. # "all" => [
  787. # {
  788. # "field" => "status"
  789. # "operator" => "less_than"
  790. # "value" => "solved"
  791. # }
  792. # {
  793. # "field" => "assignee_id"
  794. # "operator" => "is"
  795. # "value" => "current_user"
  796. # }
  797. # ]
  798. # "any" => []
  799. # }
  800. Overview.create_if_not_exists(
  801. name: zendesk_view.title,
  802. link: 'my_assigned', # TODO
  803. prio: 1000,
  804. role_id: overview_role.id,
  805. condition: {
  806. 'ticket.state_id' => {
  807. operator: 'is',
  808. value: [ 1, 2, 3, 7 ],
  809. },
  810. 'ticket.owner_id' => {
  811. operator: 'is',
  812. pre_condition: 'current_user.id',
  813. },
  814. },
  815. order: {
  816. by: 'created_at',
  817. direction: 'ASC',
  818. },
  819. view: {
  820. d: %w(title customer group created_at),
  821. s: %w(title customer group created_at),
  822. m: %w(number title customer group created_at),
  823. view_mode_default: 's',
  824. },
  825. )
  826. }
  827. end
  828. # Automations
  829. # TODO:
  830. # https://developer.zendesk.com/rest_api/docs/core/automations
  831. def import_automations
  832. @client.automations.all! { |_zendesk_automation|
  833. # "url" => "https://example.zendesk.com/api/v2/automations/60037892.json"
  834. # "id" => 60037892
  835. # "title" => "Ticket aus Facebook-Nachricht 1 ..."
  836. # "active" => true
  837. # "updated_at" => 2015-08-03 13:51:15 UTC
  838. # "created_at" => 2015-07-28 11:27:50 UTC
  839. # "actions" => [
  840. # {
  841. # "field" => "status"
  842. # "value" => "closed"
  843. # }
  844. # ]
  845. # "conditions" => {
  846. # "all" => [
  847. # {
  848. # "field" => "status"
  849. # "operator" => "is"
  850. # "value" => "solved"
  851. # }
  852. # {
  853. # "field" => "SOLVED"
  854. # "operator" => "is"
  855. # "value" => "24"
  856. # }
  857. # {
  858. # "field" => "via_type"
  859. # "operator" => "is"
  860. # "value" => "facebook"
  861. # }
  862. # ]
  863. # "any" => []
  864. # }
  865. # "position" => 10000
  866. }
  867. end
  868. # reset primary key sequences
  869. def self._reset_pk(table)
  870. return if ActiveRecord::Base.connection_config[:adapter] != 'postgresql'
  871. ActiveRecord::Base.connection.reset_pk_sequence!(table)
  872. end
  873. def get_custom_fields(custom_fields)
  874. return {} if !custom_fields
  875. fields = {}
  876. custom_fields.each { |custom_field|
  877. field_name = @zendesk_field_mapping[ custom_field['id'] ].gsub(/\s/, '_')
  878. field_value = custom_field['value']
  879. next if field_value.nil? # ignore nil values
  880. if @zendesk_ticket_field_value_mapping[ field_name ]
  881. field_value = @zendesk_ticket_field_value_mapping[ field_name ][ field_value ]
  882. end
  883. fields[ field_name.to_sym ] = field_value
  884. }
  885. fields
  886. end
  887. def get_fields(user_fields)
  888. return {} if !user_fields
  889. fields = {}
  890. user_fields.each {|key, value|
  891. fields[key] = value
  892. }
  893. fields
  894. end
  895. end