Merge branch 'develop' of github.com:martini/zammad into develop
This commit is contained in:
commit
b3e4243660
6 changed files with 1502 additions and 5 deletions
2
Gemfile
2
Gemfile
|
@ -32,6 +32,8 @@ gem 'omniauth-facebook'
|
||||||
gem 'omniauth-linkedin'
|
gem 'omniauth-linkedin'
|
||||||
gem 'omniauth-google-oauth2'
|
gem 'omniauth-google-oauth2'
|
||||||
|
|
||||||
|
gem 'zendesk_api'
|
||||||
|
|
||||||
gem 'twitter'
|
gem 'twitter'
|
||||||
gem 'koala'
|
gem 'koala'
|
||||||
gem 'mail', '~> 2.5.0'
|
gem 'mail', '~> 2.5.0'
|
||||||
|
|
61
db/migrate/20151217191239_zendesk_import_settings.rb
Normal file
61
db/migrate/20151217191239_zendesk_import_settings.rb
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
class ZendeskImportSettings < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Import Endpoint',
|
||||||
|
name: 'import_zendesk_endpoint',
|
||||||
|
area: 'Import::Zendesk',
|
||||||
|
description: 'Defines Zendesk endpoint to import users, ticket, states and articles.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: false,
|
||||||
|
name: 'import_zendesk_endpoint',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: 'https://yours.zendesk.com/api/v2',
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Import Key for requesting the Zendesk API',
|
||||||
|
name: 'import_zendesk_endpoint_key',
|
||||||
|
area: 'Import::Zendesk',
|
||||||
|
description: 'Defines Zendesk endpoint auth key.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: false,
|
||||||
|
name: 'import_zendesk_endpoint_key',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: '',
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Import User for requesting the Zendesk API',
|
||||||
|
name: 'import_zendesk_endpoint_username',
|
||||||
|
area: 'Import::Zendesk',
|
||||||
|
description: 'Defines Zendesk endpoint auth key.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'import_zendesk_endpoint_username',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: '',
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
64
db/seeds.rb
64
db/seeds.rb
|
@ -1381,10 +1381,10 @@ Setting.create_if_not_exists(
|
||||||
)
|
)
|
||||||
|
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
title: 'Import User for http basic authentiation',
|
title: 'Import User for http basic authentication',
|
||||||
name: 'import_otrs_user',
|
name: 'import_otrs_user',
|
||||||
area: 'Import::OTRS',
|
area: 'Import::OTRS',
|
||||||
description: 'Defines http basic authentiation user (only if OTRS is protected via http basic auth).',
|
description: 'Defines http basic authentication user (only if OTRS is protected via http basic auth).',
|
||||||
options: {
|
options: {
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
|
@ -1400,10 +1400,10 @@ Setting.create_if_not_exists(
|
||||||
)
|
)
|
||||||
|
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
title: 'Import Password for http basic authentiation',
|
title: 'Import Password for http basic authentication',
|
||||||
name: 'import_otrs_password',
|
name: 'import_otrs_password',
|
||||||
area: 'Import::OTRS',
|
area: 'Import::OTRS',
|
||||||
description: 'Defines http basic authentiation password (only if OTRS is protected via http basic auth).',
|
description: 'Defines http basic authentication password (only if OTRS is protected via http basic auth).',
|
||||||
options: {
|
options: {
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
|
@ -1418,6 +1418,62 @@ Setting.create_if_not_exists(
|
||||||
frontend: false
|
frontend: false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Import Endpoint',
|
||||||
|
name: 'import_zendesk_endpoint',
|
||||||
|
area: 'Import::Zendesk',
|
||||||
|
description: 'Defines Zendesk endpoint to import users, ticket, states and articles.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: false,
|
||||||
|
name: 'import_zendesk_endpoint',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: 'https://yours.zendesk.com/api/v2',
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Import Key for requesting the Zendesk API',
|
||||||
|
name: 'import_zendesk_endpoint_key',
|
||||||
|
area: 'Import::Zendesk',
|
||||||
|
description: 'Defines Zendesk endpoint auth key.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: false,
|
||||||
|
name: 'import_zendesk_endpoint_key',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: '',
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Import User for requesting the Zendesk API',
|
||||||
|
name: 'import_zendesk_endpoint_username',
|
||||||
|
area: 'Import::Zendesk',
|
||||||
|
description: 'Defines Zendesk endpoint auth key.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'import_zendesk_endpoint_username',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: '',
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
title: 'Default calendar Tickets subscriptions',
|
title: 'Default calendar Tickets subscriptions',
|
||||||
name: 'defaults_calendar_subscriptions_tickets',
|
name: 'defaults_calendar_subscriptions_tickets',
|
||||||
|
|
907
lib/import/zendesk.rb
Normal file
907
lib/import/zendesk.rb
Normal file
|
@ -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
|
471
test/integration/zendesk_import_test.rb
Normal file
471
test/integration/zendesk_import_test.rb
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'integration_test_helper'
|
||||||
|
|
||||||
|
class ZendeskImportTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
|
if !ENV['IMPORT_ZENDESK_ENDPOINT']
|
||||||
|
fail "ERROR: Need IMPORT_ZENDESK_ENDPOINT - hint IMPORT_ZENDESK_ENDPOINT='https://znuny.zendesk.com/api/v2'"
|
||||||
|
end
|
||||||
|
if !ENV['IMPORT_ZENDESK_ENDPOINT_KEY']
|
||||||
|
fail "ERROR: Need IMPORT_ZENDESK_ENDPOINT_KEY - hint IMPORT_ZENDESK_ENDPOINT_KEY='01234567899876543210'"
|
||||||
|
end
|
||||||
|
if !ENV['IMPORT_ZENDESK_ENDPOINT_USERNAME']
|
||||||
|
fail "ERROR: Need IMPORT_ZENDESK_ENDPOINT_USERNAME - hint IMPORT_ZENDESK_ENDPOINT_USERNAME='bob.ross@happylittletrees.com'"
|
||||||
|
end
|
||||||
|
|
||||||
|
Setting.set('import_zendesk_endpoint', ENV['IMPORT_ZENDESK_ENDPOINT'])
|
||||||
|
Setting.set('import_zendesk_endpoint_key', ENV['IMPORT_ZENDESK_ENDPOINT_KEY'])
|
||||||
|
Setting.set('import_zendesk_endpoint_username', ENV['IMPORT_ZENDESK_ENDPOINT_USERNAME'])
|
||||||
|
Setting.set('import_mode', true)
|
||||||
|
Import::Zendesk.start
|
||||||
|
|
||||||
|
# check statistic count
|
||||||
|
test 'check statistic' do
|
||||||
|
|
||||||
|
remote_statistic = Import::Zendesk.statistic
|
||||||
|
|
||||||
|
# retrive statistic
|
||||||
|
compare_statistic = {
|
||||||
|
'Tickets' => 143,
|
||||||
|
'TicketFields' => 13,
|
||||||
|
'UserFields' => 1,
|
||||||
|
'OrganizationFields' => 1,
|
||||||
|
'Groups' => 2,
|
||||||
|
'Organizations' => 1,
|
||||||
|
'Users' => 141,
|
||||||
|
'GroupMemberships' => 3,
|
||||||
|
'Macros' => 5,
|
||||||
|
'Views' => 11,
|
||||||
|
'Automations' => 5
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal( compare_statistic, remote_statistic, 'statistic' )
|
||||||
|
end
|
||||||
|
|
||||||
|
# check count of imported items
|
||||||
|
test 'check counts' do
|
||||||
|
assert_equal( 143, User.count, 'users' )
|
||||||
|
assert_equal( 3, Group.count, 'groups' )
|
||||||
|
assert_equal( 5, Role.count, 'roles' )
|
||||||
|
assert_equal( 2, Organization.count, 'organizations' )
|
||||||
|
assert_equal( 144, Ticket.count, 'tickets' )
|
||||||
|
assert_equal( 151, Ticket::Article.count, 'ticket articles' )
|
||||||
|
assert_equal( 2, Store.count, 'ticket article attachments' )
|
||||||
|
|
||||||
|
# TODO: Macros, Views, Automations...
|
||||||
|
end
|
||||||
|
|
||||||
|
# check imported users and permission
|
||||||
|
test 'check users' do
|
||||||
|
|
||||||
|
role_admin = Role.find_by( name: 'Admin' )
|
||||||
|
role_agent = Role.find_by( name: 'Agent' )
|
||||||
|
role_customer = Role.find_by( name: 'Customer' )
|
||||||
|
|
||||||
|
group_users = Group.find_by( name: 'Users' )
|
||||||
|
group_support = Group.find_by( name: 'Support' )
|
||||||
|
group_additional_group = Group.find_by( name: 'Additional Group' )
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
data: {
|
||||||
|
firstname: 'Bob',
|
||||||
|
lastname: 'Smith',
|
||||||
|
login: '1150734731',
|
||||||
|
email: 'bob.smith@znuny.com',
|
||||||
|
active: true,
|
||||||
|
phone: '00114124',
|
||||||
|
},
|
||||||
|
roles: [role_agent, role_admin],
|
||||||
|
groups: [group_support],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
data: {
|
||||||
|
firstname: 'Hansimerkur',
|
||||||
|
lastname: '',
|
||||||
|
login: '1202726471',
|
||||||
|
email: 'hansimerkur@znuny.com',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
roles: [role_agent, role_admin],
|
||||||
|
groups: [group_additional_group, group_support],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
data: {
|
||||||
|
firstname: 'Bernd',
|
||||||
|
lastname: 'Hofbecker',
|
||||||
|
login: '1202726611',
|
||||||
|
email: 'bernd.hofbecker@znuny.com',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
roles: [role_customer],
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
data: {
|
||||||
|
firstname: 'Zendesk',
|
||||||
|
lastname: '',
|
||||||
|
login: '1202737821',
|
||||||
|
email: 'noreply@zendesk.com',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
roles: [role_customer],
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 89,
|
||||||
|
data: {
|
||||||
|
firstname: 'Hans',
|
||||||
|
lastname: 'Peter Wurst',
|
||||||
|
login: '1205512622',
|
||||||
|
email: 'hansimerkur+zd-c1@znuny.com',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
roles: [role_customer],
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
checks.each { |check|
|
||||||
|
user = User.find( check[:id] )
|
||||||
|
|
||||||
|
assert_equal( check[:data][:firstname], user.firstname, 'firstname' )
|
||||||
|
assert_equal( check[:data][:lastname], user.lastname, 'lastname' )
|
||||||
|
assert_equal( check[:data][:login], user.login, 'login' )
|
||||||
|
assert_equal( check[:data][:email], user.email, 'email' )
|
||||||
|
assert_equal( check[:data][:phone], user.phone, 'phone' )
|
||||||
|
assert_equal( check[:data][:active], user.active, 'active' )
|
||||||
|
|
||||||
|
assert_equal( check[:roles], user.roles.to_a, "#{user.login} roles" )
|
||||||
|
assert_equal( check[:groups], user.groups.to_a, "#{user.login} groups" )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# check user fields
|
||||||
|
test 'check user fields' do
|
||||||
|
|
||||||
|
local_fields = User.column_names
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
copmare_fields = %w(
|
||||||
|
id
|
||||||
|
organization_id
|
||||||
|
login
|
||||||
|
firstname
|
||||||
|
lastname
|
||||||
|
email
|
||||||
|
image
|
||||||
|
image_source
|
||||||
|
web
|
||||||
|
password
|
||||||
|
phone
|
||||||
|
fax
|
||||||
|
mobile
|
||||||
|
department
|
||||||
|
street
|
||||||
|
zip
|
||||||
|
city
|
||||||
|
country
|
||||||
|
address
|
||||||
|
vip
|
||||||
|
verified
|
||||||
|
active
|
||||||
|
note
|
||||||
|
last_login
|
||||||
|
source
|
||||||
|
login_failed
|
||||||
|
preferences
|
||||||
|
updated_by_id
|
||||||
|
created_by_id
|
||||||
|
created_at
|
||||||
|
updated_at)
|
||||||
|
|
||||||
|
assert_equal( copmare_fields, local_fields, 'user fields' )
|
||||||
|
end
|
||||||
|
|
||||||
|
# check groups/queues
|
||||||
|
test 'check groups' do
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
data: {
|
||||||
|
name: 'Users',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
data: {
|
||||||
|
name: 'Additional Group',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
data: {
|
||||||
|
name: 'Support',
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
checks.each { |check|
|
||||||
|
group = Group.find( check[:id] )
|
||||||
|
|
||||||
|
assert_equal( check[:data][:name], group.name, 'name' )
|
||||||
|
assert_equal( check[:data][:active], group.active, 'active' )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# check imported organizations
|
||||||
|
test 'check organizations' do
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
data: {
|
||||||
|
name: 'Zammad Foundation',
|
||||||
|
note: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
data: {
|
||||||
|
name: 'Znuny',
|
||||||
|
note: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
checks.each { |check|
|
||||||
|
organization = Organization.find( check[:id] )
|
||||||
|
|
||||||
|
assert_equal( check[:data][:name], organization.name, 'name' )
|
||||||
|
assert_equal( check[:data][:note], organization.note, 'note' )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# check organization fields
|
||||||
|
test 'check organization fields' do
|
||||||
|
|
||||||
|
local_fields = Organization.column_names
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
copmare_fields = %w(
|
||||||
|
id
|
||||||
|
name
|
||||||
|
shared
|
||||||
|
active
|
||||||
|
note
|
||||||
|
updated_by_id
|
||||||
|
created_by_id
|
||||||
|
created_at
|
||||||
|
updated_at)
|
||||||
|
|
||||||
|
assert_equal( copmare_fields, local_fields, 'organization fields' )
|
||||||
|
end
|
||||||
|
|
||||||
|
# check imported tickets
|
||||||
|
test 'check tickets' do
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
data: {
|
||||||
|
title: 'test',
|
||||||
|
note: 'test email',
|
||||||
|
create_article_type_id: 1,
|
||||||
|
create_article_sender_id: 2,
|
||||||
|
article_count: 2,
|
||||||
|
state_id: 3,
|
||||||
|
group_id: 3,
|
||||||
|
priority_id: 3,
|
||||||
|
owner_id: 1,
|
||||||
|
customer_id: 6,
|
||||||
|
organization_id: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 143,
|
||||||
|
data: {
|
||||||
|
title: 'Basti ist cool',
|
||||||
|
note: 'Basti ist cool',
|
||||||
|
create_article_type_id: 8,
|
||||||
|
create_article_sender_id: 2,
|
||||||
|
article_count: 1,
|
||||||
|
state_id: 1,
|
||||||
|
group_id: 1,
|
||||||
|
priority_id: 2,
|
||||||
|
owner_id: 1,
|
||||||
|
customer_id: 143,
|
||||||
|
organization_id: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
data: {
|
||||||
|
title: 'Twitter',
|
||||||
|
note: '@DesafioCaracol sh q acaso sto se vale ver el jueg...',
|
||||||
|
create_article_type_id: 6,
|
||||||
|
create_article_sender_id: 2,
|
||||||
|
article_count: 1,
|
||||||
|
state_id: 1,
|
||||||
|
group_id: 3,
|
||||||
|
priority_id: 2,
|
||||||
|
owner_id: 1,
|
||||||
|
customer_id: 90,
|
||||||
|
organization_id: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
data: {
|
||||||
|
title: 'This is a sample ticket requested and submitted by you',
|
||||||
|
note: 'This is the first comment. Feel free to delete this sample ticket.',
|
||||||
|
create_article_type_id: 10,
|
||||||
|
create_article_sender_id: 1,
|
||||||
|
article_count: 4,
|
||||||
|
state_id: 3,
|
||||||
|
group_id: 3,
|
||||||
|
priority_id: 3,
|
||||||
|
owner_id: 1,
|
||||||
|
customer_id: 4,
|
||||||
|
organization_id: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# {
|
||||||
|
# id: ,
|
||||||
|
# data: {
|
||||||
|
# title: ,
|
||||||
|
# note: ,
|
||||||
|
# create_article_type_id: ,
|
||||||
|
# create_article_sender_id: ,
|
||||||
|
# article_count: ,
|
||||||
|
# state_id: ,
|
||||||
|
# group_id: ,
|
||||||
|
# priority_id: ,
|
||||||
|
# owner_id: ,
|
||||||
|
# customer_id: ,
|
||||||
|
# organization_id: ,
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
]
|
||||||
|
|
||||||
|
checks.each { |check|
|
||||||
|
ticket = Ticket.find( check[:id] )
|
||||||
|
|
||||||
|
assert_equal( check[:data][:title], ticket.title, 'title' )
|
||||||
|
assert_equal( check[:data][:create_article_type_id], ticket.create_article_type_id, 'created_article_type_id' )
|
||||||
|
assert_equal( check[:data][:create_article_sender_id], ticket.create_article_sender_id, 'created_article_sender_id' )
|
||||||
|
assert_equal( check[:data][:article_count], ticket.article_count, 'article_count' )
|
||||||
|
assert_equal( check[:data][:state_id], ticket.state.id, 'state_id' )
|
||||||
|
assert_equal( check[:data][:group_id], ticket.group.id, 'group_id' )
|
||||||
|
assert_equal( check[:data][:priority_id], ticket.priority.id, 'priority_id' )
|
||||||
|
assert_equal( check[:data][:owner_id], ticket.owner.id, 'owner_id' )
|
||||||
|
assert_equal( check[:data][:customer_id], ticket.customer.id, 'customer_id' )
|
||||||
|
assert_equal( check[:data][:organization_id], ticket.organization.try(:id), 'organization_id' )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'check article attachments' do
|
||||||
|
|
||||||
|
checks = [
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
data: {
|
||||||
|
count: 1,
|
||||||
|
1 => {
|
||||||
|
preferences: {
|
||||||
|
'Content-Type' => 'image/jpeg'
|
||||||
|
},
|
||||||
|
filename: '1a3496b9-53d9-494d-bbb0-e1d2e22074f8.jpeg',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
data: {
|
||||||
|
count: 1,
|
||||||
|
1 => {
|
||||||
|
preferences: {
|
||||||
|
'Content-Type' => 'image/jpeg'
|
||||||
|
},
|
||||||
|
filename: 'paris.jpg',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
checks.each { |check|
|
||||||
|
article = Ticket::Article.find(check[:id])
|
||||||
|
|
||||||
|
assert_equal( check[:data][:count], article.attachments.count, 'attachemnt count' )
|
||||||
|
|
||||||
|
(1..check[:data][:count] ).each { |attachment_counter|
|
||||||
|
|
||||||
|
attachment = article.attachments[ attachment_counter - 1 ]
|
||||||
|
compare_attachment = check[:data][ attachment_counter ]
|
||||||
|
|
||||||
|
assert_equal( compare_attachment[:filename], attachment.filename, 'attachment file name' )
|
||||||
|
|
||||||
|
assert_equal( compare_attachment[:preferences], attachment[:preferences], 'attachment preferences')
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# check ticket fields
|
||||||
|
test 'check ticket fields' do
|
||||||
|
|
||||||
|
local_fields = Ticket.column_names
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
copmare_fields = %w(
|
||||||
|
id
|
||||||
|
group_id
|
||||||
|
priority_id
|
||||||
|
state_id
|
||||||
|
organization_id
|
||||||
|
number
|
||||||
|
title
|
||||||
|
owner_id
|
||||||
|
customer_id
|
||||||
|
note
|
||||||
|
first_response
|
||||||
|
first_response_escal_date
|
||||||
|
first_response_sla_time
|
||||||
|
first_response_in_min
|
||||||
|
first_response_diff_in_min
|
||||||
|
close_time
|
||||||
|
close_time_escal_date
|
||||||
|
close_time_sla_time
|
||||||
|
close_time_in_min
|
||||||
|
close_time_diff_in_min
|
||||||
|
update_time_escal_date
|
||||||
|
updtate_time_sla_time
|
||||||
|
update_time_in_min
|
||||||
|
update_time_diff_in_min
|
||||||
|
last_contact
|
||||||
|
last_contact_agent
|
||||||
|
last_contact_customer
|
||||||
|
create_article_type_id
|
||||||
|
create_article_sender_id
|
||||||
|
article_count
|
||||||
|
escalation_time
|
||||||
|
pending_time
|
||||||
|
type
|
||||||
|
updated_by_id
|
||||||
|
created_by_id
|
||||||
|
created_at
|
||||||
|
updated_at
|
||||||
|
preferences)
|
||||||
|
|
||||||
|
assert_equal( copmare_fields, local_fields, 'ticket fields' )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue