|
@@ -0,0 +1,907 @@
|
|
|
+require 'base64'
|
|
|
+require 'zendesk_api'
|
|
|
+
|
|
|
+module Import
|
|
|
+end
|
|
|
+module Import::Zendesk
|
|
|
+
|
|
|
+ module_function
|
|
|
+
|
|
|
+ def start
|
|
|
+ Rails.logger.info 'Start import...'
|
|
|
+
|
|
|
+ # check if system is in import mode
|
|
|
+ if !Setting.get('import_mode')
|
|
|
+ fail 'System is not in import mode!'
|
|
|
+ end
|
|
|
+
|
|
|
+ initialize_client
|
|
|
+
|
|
|
+ import_fields
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ # import_oauth
|
|
|
+ # import_twitter_channel
|
|
|
+
|
|
|
+ import_groups
|
|
|
+
|
|
|
+ import_organizations
|
|
|
+
|
|
|
+ import_users
|
|
|
+
|
|
|
+ import_tickets
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ # import_sla_policies
|
|
|
+
|
|
|
+ # import_macros
|
|
|
+
|
|
|
+ # import_schedules
|
|
|
+
|
|
|
+ # import_views
|
|
|
+
|
|
|
+ # import_automations
|
|
|
+
|
|
|
+ Setting.set( 'system_init_done', true )
|
|
|
+ Setting.set( 'import_mode', false )
|
|
|
+
|
|
|
+ true
|
|
|
+ end
|
|
|
+
|
|
|
+ def statistic
|
|
|
+
|
|
|
+ # check cache
|
|
|
+ cache = Cache.get('import_zendesk_stats')
|
|
|
+ if cache
|
|
|
+ return cache
|
|
|
+ end
|
|
|
+
|
|
|
+ initialize_client
|
|
|
+
|
|
|
+ # retrive statistic
|
|
|
+ statistic = {
|
|
|
+ 'Tickets' => 0,
|
|
|
+ 'TicketFields' => 0,
|
|
|
+ 'UserFields' => 0,
|
|
|
+ 'OrganizationFields' => 0,
|
|
|
+ 'Groups' => 0,
|
|
|
+ 'Organizations' => 0,
|
|
|
+ 'Users' => 0,
|
|
|
+ 'GroupMemberships' => 0,
|
|
|
+ 'Macros' => 0,
|
|
|
+ 'Views' => 0,
|
|
|
+ 'Automations' => 0,
|
|
|
+ }
|
|
|
+
|
|
|
+ statistic.each { |object, _score|
|
|
|
+
|
|
|
+ counter = 0
|
|
|
+ @client.send( object.underscore.to_sym ).all do |_resource|
|
|
|
+ counter += 1
|
|
|
+ end
|
|
|
+
|
|
|
+ statistic[ object ] = counter
|
|
|
+ }
|
|
|
+
|
|
|
+ if statistic
|
|
|
+ Cache.write('import_zendesk_stats', statistic)
|
|
|
+ end
|
|
|
+ statistic
|
|
|
+ end
|
|
|
+
|
|
|
+ private
|
|
|
+
|
|
|
+ def initialize_client
|
|
|
+ return nil if @client
|
|
|
+
|
|
|
+ @client = ZendeskAPI::Client.new do |config|
|
|
|
+ config.url = Setting.get('import_zendesk_endpoint')
|
|
|
+
|
|
|
+ # Basic / Token Authentication
|
|
|
+ config.username = Setting.get('import_zendesk_endpoint_username')
|
|
|
+ config.token = Setting.get('import_zendesk_endpoint_key')
|
|
|
+
|
|
|
+ # when hitting the rate limit, sleep automatically,
|
|
|
+ # then retry the request.
|
|
|
+ config.retry = true
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ def mapping_state(zendesk_state)
|
|
|
+
|
|
|
+ mapping = {
|
|
|
+ 'pending' => 'pending reminder',
|
|
|
+ 'solved' => 'closed',
|
|
|
+ }
|
|
|
+ return zendesk_state if !mapping[zendesk_state]
|
|
|
+ mapping[zendesk_state]
|
|
|
+ end
|
|
|
+
|
|
|
+ def mapping_priority(zendesk_priority)
|
|
|
+
|
|
|
+ mapping = {
|
|
|
+ 'low' => '1 low',
|
|
|
+ nil => '2 normal',
|
|
|
+ 'normal' => '2 normal',
|
|
|
+ 'high' => '3 high',
|
|
|
+ 'urgent' => '3 high',
|
|
|
+ }
|
|
|
+ mapping[zendesk_priority]
|
|
|
+ end
|
|
|
+
|
|
|
+ # NOT IMPLEMENTED YET
|
|
|
+ def mapping_type(zendesk_type)
|
|
|
+
|
|
|
+ mapping = {
|
|
|
+ nil => '',
|
|
|
+ 'question' => '',
|
|
|
+ 'incident' => '',
|
|
|
+ 'problem' => '',
|
|
|
+ 'task' => '',
|
|
|
+ }
|
|
|
+ return zendesk_type if !mapping[zendesk_type]
|
|
|
+ mapping[zendesk_type]
|
|
|
+ end
|
|
|
+
|
|
|
+ def mapping_ticket_field(zendesk_field)
|
|
|
+
|
|
|
+ mapping = {
|
|
|
+ 'subject' => 'title',
|
|
|
+ 'description' => 'note',
|
|
|
+ 'status' => 'state_id',
|
|
|
+ 'tickettype' => 'type',
|
|
|
+ 'priority' => 'priority_id',
|
|
|
+ 'group' => 'group_id',
|
|
|
+ 'assignee' => 'owner_id',
|
|
|
+ }
|
|
|
+ return zendesk_field if !mapping[zendesk_field]
|
|
|
+ mapping[zendesk_field]
|
|
|
+ end
|
|
|
+
|
|
|
+ # FILTER:
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/views#conditions-reference
|
|
|
+ def mapping_filter(zendesk_filter)
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ # Ticket Fields
|
|
|
+ # User Fields
|
|
|
+ # Organization Fields
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/ticket_fields
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/user_fields
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/organization_fields
|
|
|
+ def import_fields
|
|
|
+
|
|
|
+ %w(Ticket User Organization).each { |local_object|
|
|
|
+
|
|
|
+ local_fields = local_object.constantize.column_names
|
|
|
+
|
|
|
+ @client.send("#{local_object.downcase}_fields").all { |object_field|
|
|
|
+
|
|
|
+ if local_object == 'Ticket'
|
|
|
+ mapped_object_field = method("mapping_#{local_object.downcase}_field").call( object_field.type )
|
|
|
+
|
|
|
+ next if local_fields.include?( mapped_object_field )
|
|
|
+ end
|
|
|
+
|
|
|
+ import_field(local_object, object_field)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ def import_field(local_object, zendesk_field)
|
|
|
+
|
|
|
+ name = ''
|
|
|
+ if local_object == 'Ticket'
|
|
|
+ name = zendesk_field.title
|
|
|
+ else
|
|
|
+ name = zendesk_field['key'] # TODO: y?!
|
|
|
+ end
|
|
|
+
|
|
|
+ @zendesk_ticket_field_mapping ||= {}
|
|
|
+ @zendesk_ticket_field_mapping[ zendesk_field.id ] = name
|
|
|
+
|
|
|
+ data_type = zendesk_field.type
|
|
|
+ data_option = {
|
|
|
+ null: !zendesk_field.required,
|
|
|
+ note: zendesk_field.description,
|
|
|
+ }
|
|
|
+
|
|
|
+ if zendesk_field.type == 'date'
|
|
|
+
|
|
|
+ data_option = {
|
|
|
+ future: true,
|
|
|
+ past: true,
|
|
|
+ }.merge( data_option )
|
|
|
+
|
|
|
+ elsif zendesk_field.type == 'regexp'
|
|
|
+
|
|
|
+ data_type = 'input'
|
|
|
+ data_option = {
|
|
|
+ type: 'text',
|
|
|
+ regex: zendesk_field.regexp_for_validation,
|
|
|
+ }.merge( data_option )
|
|
|
+
|
|
|
+ elsif zendesk_field.type == 'text'
|
|
|
+
|
|
|
+ data_type = 'input'
|
|
|
+ data_option = {
|
|
|
+ type: zendesk_field.type,
|
|
|
+ }.merge( data_option )
|
|
|
+
|
|
|
+ elsif zendesk_field.type == 'textarea'
|
|
|
+
|
|
|
+ data_type = 'input'
|
|
|
+ data_option = {
|
|
|
+ type: zendesk_field.type,
|
|
|
+ }.merge( data_option )
|
|
|
+
|
|
|
+ elsif zendesk_field.type == 'tagger'
|
|
|
+
|
|
|
+ # \"custom_field_options\"=>[{\"id\"=>28353445
|
|
|
+ # \"name\"=>\"Another Value\"
|
|
|
+ # \"raw_name\"=>\"Another Value\"
|
|
|
+ # \"value\"=>\"anotherkey\"}
|
|
|
+ # {\"id\"=>28353425
|
|
|
+ # \"name\"=>\"Value 1\"
|
|
|
+ # \"raw_name\"=>\"Value 1\"
|
|
|
+ # \"value\"=>\"key1\"}
|
|
|
+ # {\"id\"=>28353435
|
|
|
+ # \"name\"=>\"Value 2\"
|
|
|
+ # \"raw_name\"=>\"Value 2\"
|
|
|
+ # \"value\"=>\"key2\"}]}>
|
|
|
+
|
|
|
+ # "
|
|
|
+
|
|
|
+ options = {}
|
|
|
+ @zendesk_ticket_field_value_mapping ||= {}
|
|
|
+ zendesk_field.custom_field_options.each { |entry|
|
|
|
+
|
|
|
+ if local_object == 'Ticket'
|
|
|
+ @zendesk_ticket_field_value_mapping[ name ] ||= {}
|
|
|
+ @zendesk_ticket_field_value_mapping[ name ][ entry['id'] ] = entry['value']
|
|
|
+ end
|
|
|
+
|
|
|
+ options[ entry['value'] ] = entry['name']
|
|
|
+ }
|
|
|
+
|
|
|
+ data_type = 'select'
|
|
|
+ data_option = {
|
|
|
+ options: options,
|
|
|
+ }.merge( data_option )
|
|
|
+ end
|
|
|
+
|
|
|
+ screens = {
|
|
|
+ view: {
|
|
|
+ '-all-' => {
|
|
|
+ shown: true,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if zendesk_field.visible_in_portal || !zendesk_field.required_in_portal
|
|
|
+ screens = {
|
|
|
+ edit: {
|
|
|
+ Customer: {
|
|
|
+ shown: zendesk_field.visible_in_portal,
|
|
|
+ null: !zendesk_field.required_in_portal,
|
|
|
+ },
|
|
|
+ }.merge(screens)
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ ObjectManager::Attribute.add(
|
|
|
+ object: local_object,
|
|
|
+ name: name,
|
|
|
+ display: zendesk_field.title,
|
|
|
+ data_type: data_type,
|
|
|
+ data_option: data_option,
|
|
|
+ editable: !zendesk_field.removable,
|
|
|
+ active: zendesk_field.active,
|
|
|
+ screens: screens,
|
|
|
+ pending_migration: false,
|
|
|
+ position: zendesk_field.position,
|
|
|
+ created_by_id: 1,
|
|
|
+ updated_by_id: 1,
|
|
|
+ )
|
|
|
+ end
|
|
|
+
|
|
|
+ # OAuth
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/oauth_tokens
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/oauth_clients
|
|
|
+ def import_oauth
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ # Twitter
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/twitter_channel
|
|
|
+ def import_twitter
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ # Groups
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/groups
|
|
|
+ def import_groups
|
|
|
+
|
|
|
+ @zendesk_group_mapping = {}
|
|
|
+ @client.groups.all { |zendesk_group|
|
|
|
+
|
|
|
+ local_group = Group.create_if_not_exists(
|
|
|
+ name: zendesk_group.name,
|
|
|
+ active: !zendesk_group.deleted,
|
|
|
+ updated_by_id: 1,
|
|
|
+ created_by_id: 1
|
|
|
+ )
|
|
|
+
|
|
|
+ @zendesk_group_mapping[ zendesk_group.id ] = local_group.id
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ # Organizations
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/organizations
|
|
|
+ def import_organizations
|
|
|
+
|
|
|
+ @zendesk_organization_mapping = {}
|
|
|
+
|
|
|
+ @client.organizations.each { |zendesk_organization|
|
|
|
+
|
|
|
+ local_organization_fields = {
|
|
|
+ name: zendesk_organization.name,
|
|
|
+ note: zendesk_organization.note,
|
|
|
+ shared: zendesk_organization.shared_tickets,
|
|
|
+ # shared: zendesk_organization.shared_comments, # TODO, not yet implemented
|
|
|
+ # }.merge(zendesk_organization.organization_fields) # TODO
|
|
|
+ }
|
|
|
+
|
|
|
+ local_organization = Organization.create_if_not_exists( local_organization_fields )
|
|
|
+
|
|
|
+ @zendesk_organization_mapping[ zendesk_organization.id ] = local_organization.id
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ # Users
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/users
|
|
|
+ def import_users
|
|
|
+ import_group_memberships
|
|
|
+ import_custom_roles
|
|
|
+
|
|
|
+ @zendesk_user_mapping = {}
|
|
|
+
|
|
|
+ role_admin = Role.find_by( name: 'Admin' )
|
|
|
+ role_agent = Role.find_by( name: 'Agent' )
|
|
|
+ role_customer = Role.find_by( name: 'Customer' )
|
|
|
+
|
|
|
+ @client.users.all { |zendesk_user|
|
|
|
+
|
|
|
+ local_user_fields = {
|
|
|
+ login: zendesk_user.id.to_s, # Zendesk users may have no other identifier than the ID, e.g. twitter users
|
|
|
+ firstname: zendesk_user.name,
|
|
|
+ email: zendesk_user.email,
|
|
|
+ phone: zendesk_user.phone,
|
|
|
+ password: '',
|
|
|
+ active: !zendesk_user.suspended,
|
|
|
+ groups: [],
|
|
|
+ roles: [],
|
|
|
+ note: zendesk_user.notes,
|
|
|
+ verified: zendesk_user.verified,
|
|
|
+ organization_id: @zendesk_organization_mapping[ zendesk_user.organization_id ],
|
|
|
+ last_login: zendesk_user.last_login_at,
|
|
|
+ }
|
|
|
+
|
|
|
+ if @zendesk_user_group_mapping[ zendesk_user.id ]
|
|
|
+
|
|
|
+ @zendesk_user_group_mapping[ zendesk_user.id ].each { |zendesk_group_id|
|
|
|
+
|
|
|
+ local_group_id = @zendesk_group_mapping[ zendesk_group_id ]
|
|
|
+
|
|
|
+ next if !local_group_id
|
|
|
+
|
|
|
+ group = Group.find( local_group_id )
|
|
|
+
|
|
|
+ local_user_fields[:groups].push group
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ if zendesk_user.role.name == 'end-user'
|
|
|
+ local_user_fields[:roles].push role_customer
|
|
|
+
|
|
|
+ elsif zendesk_user.role.name == 'agent'
|
|
|
+
|
|
|
+ local_user_fields[:roles].push role_agent
|
|
|
+
|
|
|
+ if !zendesk_user.restricted_agent
|
|
|
+ local_user_fields[:roles].push role_admin
|
|
|
+ end
|
|
|
+
|
|
|
+ elsif zendesk_user.role.name == 'admin'
|
|
|
+ local_user_fields[:roles].push role_agent
|
|
|
+ local_user_fields[:roles].push role_admin
|
|
|
+ end
|
|
|
+
|
|
|
+ if zendesk_user.photo && zendesk_user.photo.content_url
|
|
|
+ local_user_fields[:image_source] = zendesk_user.photo.content_url
|
|
|
+ end
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ # local_user_fields = local_user_fields.merge( user.user_fields )
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ # user.custom_role_id (Enterprise only)
|
|
|
+ local_user = User.create_or_update( local_user_fields )
|
|
|
+
|
|
|
+ @zendesk_user_mapping[ zendesk_user.id ] = local_user.id
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ # Group Memberships
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/group_memberships
|
|
|
+ def import_group_memberships
|
|
|
+
|
|
|
+ @zendesk_user_group_mapping = {}
|
|
|
+
|
|
|
+ @client.group_memberships.all { |group_membership|
|
|
|
+ @zendesk_user_group_mapping[ group_membership.user_id ] ||= []
|
|
|
+ @zendesk_user_group_mapping[ group_membership.user_id ].push group_membership.group_id
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ # Custom Roles (Enterprise only)
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/custom_roles
|
|
|
+ def import_custom_roles
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ # Tickets
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/tickets
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/ticket_comments#ticket-comments
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/ticket_audits#the-via-object
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/help_center/article_attachments
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/ticket_audits # v2
|
|
|
+ def import_tickets
|
|
|
+
|
|
|
+ article_sender_customer = Ticket::Article::Sender.find_by(name: 'Customer')
|
|
|
+ article_sender_agent = Ticket::Article::Sender.find_by(name: 'Agent')
|
|
|
+ article_sender_system = Ticket::Article::Sender.find_by(name: 'System')
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ article_type_web = Ticket::Article::Type.find_by(name: 'web')
|
|
|
+ article_type_note = Ticket::Article::Type.find_by(name: 'note')
|
|
|
+ article_type_email = Ticket::Article::Type.find_by(name: 'email')
|
|
|
+ article_type_twitter_status = Ticket::Article::Type.find_by(name: 'twitter status')
|
|
|
+ article_type_twitter_dm = Ticket::Article::Type.find_by(name: 'twitter direct-message')
|
|
|
+ article_type_facebook_feed_post = Ticket::Article::Type.find_by(name: 'facebook feed post')
|
|
|
+ article_type_facebook_feed_comment = Ticket::Article::Type.find_by(name: 'facebook feed comment')
|
|
|
+
|
|
|
+ @client.tickets.all { |zendesk_ticket|
|
|
|
+
|
|
|
+ zendesk_ticket_fields = {}
|
|
|
+ zendesk_ticket.custom_fields.each { |zendesk_ticket_field|
|
|
|
+
|
|
|
+ field_name = @zendesk_ticket_field_mapping[ zendesk_ticket_field['id'] ]
|
|
|
+ field_value = zendesk_ticket_field['value']
|
|
|
+ if @zendesk_ticket_field_value_mapping[ field_name ]
|
|
|
+ field_value = @zendesk_ticket_field_value_mapping[ field_name ][ field_value ]
|
|
|
+ end
|
|
|
+
|
|
|
+ zendesk_ticket_fields[ field_name ] = field_value
|
|
|
+ }
|
|
|
+
|
|
|
+ local_ticket_fields = {
|
|
|
+ title: zendesk_ticket.subject,
|
|
|
+ note: zendesk_ticket.description,
|
|
|
+ group_id: @zendesk_group_mapping[ zendesk_ticket.group_id ] || 1, # TODO
|
|
|
+ customer_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ],
|
|
|
+ organization_id: @zendesk_organization_mapping[ zendesk_ticket.organization_id ],
|
|
|
+ state: Ticket::State.lookup( name: mapping_state( zendesk_ticket.status ) ),
|
|
|
+ priority: Ticket::Priority.lookup( name: mapping_priority( zendesk_ticket.priority ) ),
|
|
|
+ pending_time: zendesk_ticket.due_at,
|
|
|
+ updated_at: zendesk_ticket.updated_at,
|
|
|
+ created_at: zendesk_ticket.created_at,
|
|
|
+ updated_by_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ],
|
|
|
+ created_by_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ],
|
|
|
+ # }.merge(zendesk_ticket_fields) TODO
|
|
|
+ }
|
|
|
+
|
|
|
+ ticket_author = User.find( @zendesk_user_mapping[ zendesk_ticket.requester_id ] )
|
|
|
+
|
|
|
+ if ticket_author.role?('Customer')
|
|
|
+ local_ticket_fields[:create_article_sender_id] = article_sender_customer.id
|
|
|
+ elsif ticket_author.role?('Agent')
|
|
|
+ local_ticket_fields[:create_article_sender_id] = article_sender_agent.id
|
|
|
+ else
|
|
|
+ local_ticket_fields[:create_article_sender_id] = article_sender_system.id
|
|
|
+ end
|
|
|
+
|
|
|
+ # TODO: zendesk_ticket.external_id ?
|
|
|
+ if zendesk_ticket.via.channel == 'web'
|
|
|
+ local_ticket_fields[:create_article_type_id] = article_type_note.id # TODO
|
|
|
+ elsif zendesk_ticket.via.channel == 'email'
|
|
|
+ local_ticket_fields[:create_article_type_id] = article_type_email.id
|
|
|
+ elsif zendesk_ticket.via.channel == 'sample_ticket'
|
|
|
+ local_ticket_fields[:create_article_type_id] = article_type_note.id # TODO
|
|
|
+ elsif zendesk_ticket.via.channel == 'twitter'
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ if zendesk_ticket.via.source.rel == 'mention'
|
|
|
+ local_ticket_fields[:create_article_type_id] = article_type_twitter_status.id
|
|
|
+ else
|
|
|
+ local_ticket_fields[:create_article_type_id] = article_type_twitter_dm.id
|
|
|
+ end
|
|
|
+
|
|
|
+ elsif zendesk_ticket.via.channel == 'facebook'
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ if zendesk_ticket.via.source.rel == 'post'
|
|
|
+ local_ticket_fields[:create_article_type_id] = article_type_facebook_feed_post.id
|
|
|
+ else
|
|
|
+ local_ticket_fields[:create_article_type_id] = article_type_facebook_feed_comment.id
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ local_ticket = Ticket.create( local_ticket_fields )
|
|
|
+
|
|
|
+ zendesk_ticket.tags.each { |tag|
|
|
|
+ Tag.tag_add(
|
|
|
+ object: 'Ticket',
|
|
|
+ o_id: local_ticket.id,
|
|
|
+ item: tag.id,
|
|
|
+ created_by_id: @zendesk_user_mapping[ zendesk_ticket.requester_id ],
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ zendesk_ticket.comments.each { |zendesk_article|
|
|
|
+
|
|
|
+ # p zendesk_article.inspect
|
|
|
+
|
|
|
+ # "#<ZendeskAPI::Ticket::Comment {\"id\"=>31964468391,
|
|
|
+ # \"type\"=>\"Comment\",
|
|
|
+ # \"author_id\"=>1150734731,
|
|
|
+ # \"body\"=>\"This is the first comment. Feel free to delete this sample ticket.\",
|
|
|
+ # \"html_body\"=>\"<div class=\\\"zd-comment\\\"><p>This is the first comment. Feel free to delete this sample ticket.</p></div>\",
|
|
|
+ # \"public\"=>true,
|
|
|
+ # \"attachments\"=>[],
|
|
|
+ # \"audit_id\"=>31964468381,
|
|
|
+ # \"via\"=>{\"channel\"=>\"sample_ticket\",
|
|
|
+ # \"source\"=>{\"from\"=>{},
|
|
|
+ # \"to\"=>{},
|
|
|
+ # \"rel\"=>nil}},
|
|
|
+ # \"metadata\"=>{\"system\"=>{},
|
|
|
+ # \"custom\"=>{}},
|
|
|
+ # \"created_at\"=>2015-07-19 22:41:43 UTC}
|
|
|
+ # "
|
|
|
+ local_article_fields = {
|
|
|
+ ticket_id: local_ticket.id,
|
|
|
+ body: zendesk_article.html_body,
|
|
|
+ internal: !zendesk_article.public,
|
|
|
+ updated_by_id: @zendesk_user_mapping[ zendesk_article.author_id ],
|
|
|
+ created_by_id: @zendesk_user_mapping[ zendesk_article.author_id ],
|
|
|
+ }
|
|
|
+
|
|
|
+ article_author = User.find( @zendesk_user_mapping[ zendesk_article.author_id ] )
|
|
|
+
|
|
|
+ if article_author.role?('Customer')
|
|
|
+ local_article_fields[:sender_id] = article_sender_customer.id
|
|
|
+ elsif article_author.role?('Agent')
|
|
|
+ local_article_fields[:sender_id] = article_sender_agent.id
|
|
|
+ else
|
|
|
+ local_article_fields[:sender_id] = article_sender_system.id
|
|
|
+ end
|
|
|
+
|
|
|
+ if zendesk_article.via.channel == 'web'
|
|
|
+ local_article_fields[:message_id] = zendesk_article.id
|
|
|
+ local_article_fields[:type_id] = article_type_note.id # TODO
|
|
|
+ elsif zendesk_article.via.channel == 'email'
|
|
|
+ local_article_fields[:from] = zendesk_article.via.source.from.address
|
|
|
+ local_article_fields[:to] = zendesk_article.via.source.to.address # TODO: or zendesk_article.via.from.original_recipients=[\"martin.edenhofer42@gmail.com\", \"support@znunyhelp.zendesk.com\"]
|
|
|
+ local_article_fields[:message_id] = zendesk_article.id
|
|
|
+ local_article_fields[:type_id] = article_type_email.id
|
|
|
+ elsif zendesk_article.via.channel == 'sample_ticket'
|
|
|
+ local_article_fields[:message_id] = zendesk_article.id
|
|
|
+ local_article_fields[:type_id] = article_type_note.id # TODO
|
|
|
+ elsif zendesk_article.via.channel == 'twitter'
|
|
|
+ local_article_fields[:message_id] = zendesk_article.id
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ if zendesk_article.via.source.rel == 'mention'
|
|
|
+ local_article_fields[:type_id] = article_type_twitter_status.id
|
|
|
+ else
|
|
|
+ local_article_fields[:type_id] = article_type_twitter_dm.id
|
|
|
+ end
|
|
|
+
|
|
|
+ elsif zendesk_article.via.channel == 'facebook'
|
|
|
+
|
|
|
+ local_article_fields[:from] = zendesk_article.via.source.from.facebook_id
|
|
|
+ local_article_fields[:to] = zendesk_article.via.source.to.facebook_id
|
|
|
+ local_article_fields[:message_id] = zendesk_article.id
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ if zendesk_article.via.source.rel == 'post'
|
|
|
+ local_article_fields[:type_id] = article_type_facebook_feed_post.id
|
|
|
+ else
|
|
|
+ local_article_fields[:type_id] = article_type_facebook_feed_comment.id
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # create article
|
|
|
+ local_article = Ticket::Article.create( local_article_fields )
|
|
|
+
|
|
|
+ zendesk_attachments = zendesk_article.attachments
|
|
|
+
|
|
|
+ next if zendesk_attachments.size == 0
|
|
|
+
|
|
|
+ local_attachments = local_article.attachments
|
|
|
+
|
|
|
+ zendesk_attachments.each { |zendesk_attachment|
|
|
|
+
|
|
|
+ response = UserAgent.get(
|
|
|
+ zendesk_attachment.content_url,
|
|
|
+ {},
|
|
|
+ {
|
|
|
+ open_timeout: 10,
|
|
|
+ read_timeout: 60,
|
|
|
+ },
|
|
|
+ )
|
|
|
+
|
|
|
+ if !response.success?
|
|
|
+ Rails.logger.error response.error
|
|
|
+ next
|
|
|
+ end
|
|
|
+
|
|
|
+ local_attachment = Store.add(
|
|
|
+ object: 'Ticket::Article',
|
|
|
+ o_id: local_article.id,
|
|
|
+ data: response.body,
|
|
|
+ filename: zendesk_attachment.file_name,
|
|
|
+ preferences: {
|
|
|
+ 'Content-Type' => zendesk_attachment.content_type
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ # SLA Policies
|
|
|
+ # TODO:
|
|
|
+ # https://github.com/zendesk/zendesk_api_client_rb/issues/271
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/sla_policies
|
|
|
+ def import_sla_policies
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ # Macros
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/macros
|
|
|
+ def import_macros
|
|
|
+
|
|
|
+ @client.macros.all { |macro|
|
|
|
+
|
|
|
+ # TODO
|
|
|
+ next if !macro.active
|
|
|
+
|
|
|
+ # "url"=>"https://znunyhelp.zendesk.com/api/v2/macros/59511191.json"
|
|
|
+ # "id"=>59511191
|
|
|
+ # "title"=>"Herabstufen und informieren"
|
|
|
+ # "active"=>true
|
|
|
+ # "updated_at"=>2015-08-03 13:51:14 UTC
|
|
|
+ # "created_at"=>2015-07-19 22:41:42 UTC
|
|
|
+ # "restriction"=>nil
|
|
|
+ # "actions"=>[
|
|
|
+ # {
|
|
|
+ # "field"=>"priority"
|
|
|
+ # "value"=>"low"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "field"=>"comment_value"
|
|
|
+ # "value"=>"Das Verkehrsaufkommen ist g....."
|
|
|
+ # }
|
|
|
+ # ]
|
|
|
+
|
|
|
+ perform = {}
|
|
|
+ macro.actions.each { |action|
|
|
|
+
|
|
|
+ # TODO: ID fields
|
|
|
+ perform["ticket.#{action.field}"] = action.value
|
|
|
+ }
|
|
|
+
|
|
|
+ Macro.create_if_not_exists(
|
|
|
+ name: macro.title,
|
|
|
+ perform: perform,
|
|
|
+ note: '',
|
|
|
+ active: macro.active,
|
|
|
+ )
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ # Schedulers
|
|
|
+ # TODO:
|
|
|
+ # https://github.com/zendesk/zendesk_api_client_rb/issues/281
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/schedules
|
|
|
+ def import_schedules
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+ # Views
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/views
|
|
|
+ def import_views
|
|
|
+
|
|
|
+ @client.views.all { |view|
|
|
|
+
|
|
|
+ # "url" => "https://znunyhelp.zendesk.com/api/v2/views/59511071.json"
|
|
|
+ # "id" => 59511071
|
|
|
+ # "title" => "Ihre Tickets"
|
|
|
+ # "active" => true
|
|
|
+ # "updated_at" => 2015-08-03 13:51:14 UTC
|
|
|
+ # "created_at" => 2015-07-19 22:41:42 UTC
|
|
|
+ # "restriction" => nil
|
|
|
+ # "sla_id" => nil
|
|
|
+ # "execution" => {
|
|
|
+ # "group_by" => "status"
|
|
|
+ # "group_order" => "asc"
|
|
|
+ # "sort_by" => "score"
|
|
|
+ # "sort_order" => "desc"
|
|
|
+ # "group" => {
|
|
|
+ # "id" => "status"
|
|
|
+ # "title" => "Status"
|
|
|
+ # "order" => "asc"
|
|
|
+ # }
|
|
|
+ # "sort" => {
|
|
|
+ # "id" => "score"
|
|
|
+ # "title" => "Score"
|
|
|
+ # "order" => "desc"
|
|
|
+ # }
|
|
|
+ # "columns" => [
|
|
|
+ # {
|
|
|
+ # "id" => "score"
|
|
|
+ # "title" => "Score"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "subject"
|
|
|
+ # "title" => "Subject"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "requester"
|
|
|
+ # "title" => "Requester"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "created"
|
|
|
+ # "title" => "Requested"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "type"
|
|
|
+ # "title" => "Type"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "priority"
|
|
|
+ # "title" => "Priority"
|
|
|
+ # }
|
|
|
+ # ]
|
|
|
+ # "fields" => [
|
|
|
+ # {
|
|
|
+ # "id" => "score"
|
|
|
+ # "title" => "Score"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "subject"
|
|
|
+ # "title" => "Subject"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "requester"
|
|
|
+ # "title" => "Requester"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "created"
|
|
|
+ # "title" => "Requested"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "type"
|
|
|
+ # "title" => "Type"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "id" => "priority"
|
|
|
+ # "title" => "Priority"
|
|
|
+ # }
|
|
|
+ # ]
|
|
|
+ # "custom_fields" => []
|
|
|
+ # }
|
|
|
+ # "conditions" => {
|
|
|
+ # "all" => [
|
|
|
+ # {
|
|
|
+ # "field" => "status"
|
|
|
+ # "operator" => "less_than"
|
|
|
+ # "value" => "solved"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "field" => "assignee_id"
|
|
|
+ # "operator" => "is"
|
|
|
+ # "value" => "current_user"
|
|
|
+ # }
|
|
|
+ # ]
|
|
|
+ # "any" => []
|
|
|
+ # }
|
|
|
+
|
|
|
+ Overview.create_if_not_exists(
|
|
|
+ name: view.title,
|
|
|
+ link: 'my_assigned', # TODO
|
|
|
+ prio: 1000,
|
|
|
+ role_id: overview_role.id,
|
|
|
+ condition: {
|
|
|
+ 'ticket.state_id' => {
|
|
|
+ operator: 'is',
|
|
|
+ value: [ 1, 2, 3, 7 ],
|
|
|
+ },
|
|
|
+ 'ticket.owner_id' => {
|
|
|
+ operator: 'is',
|
|
|
+ pre_condition: 'current_user.id',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ order: {
|
|
|
+ by: 'created_at',
|
|
|
+ direction: 'ASC',
|
|
|
+ },
|
|
|
+ view: {
|
|
|
+ d: %w(title customer group created_at),
|
|
|
+ s: %w(title customer group created_at),
|
|
|
+ m: %w(number title customer group created_at),
|
|
|
+ view_mode_default: 's',
|
|
|
+ },
|
|
|
+ )
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+ # Automations
|
|
|
+ # TODO:
|
|
|
+ # https://developer.zendesk.com/rest_api/docs/core/automations
|
|
|
+ def import_automations
|
|
|
+
|
|
|
+ @client.automations.all { |automation|
|
|
|
+
|
|
|
+ # "url" => "https://znunyhelp.zendesk.com/api/v2/automations/60037892.json"
|
|
|
+ # "id" => 60037892
|
|
|
+ # "title" => "Ticket aus Facebook-Nachricht 1 ..."
|
|
|
+ # "active" => true
|
|
|
+ # "updated_at" => 2015-08-03 13:51:15 UTC
|
|
|
+ # "created_at" => 2015-07-28 11:27:50 UTC
|
|
|
+ # "actions" => [
|
|
|
+ # {
|
|
|
+ # "field" => "status"
|
|
|
+ # "value" => "closed"
|
|
|
+ # }
|
|
|
+ # ]
|
|
|
+ # "conditions" => {
|
|
|
+ # "all" => [
|
|
|
+ # {
|
|
|
+ # "field" => "status"
|
|
|
+ # "operator" => "is"
|
|
|
+ # "value" => "solved"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "field" => "SOLVED"
|
|
|
+ # "operator" => "is"
|
|
|
+ # "value" => "24"
|
|
|
+ # }
|
|
|
+ # {
|
|
|
+ # "field" => "via_type"
|
|
|
+ # "operator" => "is"
|
|
|
+ # "value" => "facebook"
|
|
|
+ # }
|
|
|
+ # ]
|
|
|
+ # "any" => []
|
|
|
+ # }
|
|
|
+ # "position" => 10000
|
|
|
+
|
|
|
+ }
|
|
|
+ end
|
|
|
+
|
|
|
+end
|