zendesk.rb 29 KB

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