Added init version of clearbit integration.

This commit is contained in:
Martin Edenhofer 2016-04-26 01:04:59 +02:00
parent 62d35d2a0e
commit e06f4ee7fe
22 changed files with 1865 additions and 99 deletions

View file

@ -156,6 +156,17 @@ job_integration_slack:
- ruby -I test test/integration/slack_test.rb
- rake db:drop
job_integration_clearbit:
stage: test
tags:
- core
script:
- export RAILS_ENV=test
- rake db:create
- rake db:migrate
- ruby -I test test/integration/clearbit_test.rb
- rake db:drop
job_integration_es_mysql:
stage: test
tags:

View file

@ -32,8 +32,6 @@ gem 'omniauth-facebook'
gem 'omniauth-linkedin'
gem 'omniauth-google-oauth2'
gem 'zendesk_api'
gem 'twitter'
gem 'koala'
gem 'mail'
@ -90,6 +88,8 @@ gem 'browser'
# integrations
gem 'slack-notifier'
gem 'clearbit'
gem 'zendesk_api'
# event machine
gem 'eventmachine'

View file

@ -54,6 +54,8 @@ GEM
childprocess (0.5.9)
ffi (~> 1.0, >= 1.0.11)
clavius (1.0.2)
clearbit (0.2.3)
nestful (~> 1.1.0)
coderay (1.1.1)
coffee-rails (4.1.1)
coffee-script (>= 2.2.0)
@ -134,7 +136,7 @@ GEM
faraday
multi_json
libv8 (3.16.14.13)
listen (3.0.6)
listen (3.1.1)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9.7)
loofah (2.0.3)
@ -154,6 +156,7 @@ GEM
mysql2 (0.3.20)
naught (1.1.0)
nenv (0.3.0)
nestful (1.1.1)
net-ldap (0.14.0)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
@ -323,6 +326,7 @@ DEPENDENCIES
autoprefixer-rails (>= 5.2)
biz
browser
clearbit
coffee-rails
coffee-script-source
coffeelint

View file

@ -0,0 +1,165 @@
class Index extends App.ControllerIntegrationBase
featureIntegration: 'clearbit_integration'
featureName: 'Clearbit'
featureConfig: 'clearbit_config'
description: [
['Automatically enrich your customers and organizations with fresh, up-to-date intel. Map data directly to object fields.
']
]
render: =>
super
new Form(
el: @$('.js-form')
)
new App.HttpLog(
el: @$('.js-log')
facility: 'clearbit'
)
class Form extends App.Controller
events:
'submit form': 'update'
'click .js-userSync .js-add': 'addUserSync'
'click .js-organizationSync .js-add': 'addOrganizationSync'
'click .js-userSync .js-remove': 'removeRow'
'click .js-organizationSync .js-remove': 'removeRow'
constructor: ->
super
# check authentication
return if !@authenticate()
@subscribeId = App.Setting.subscribe(@render, initFetch: true, clear: false)
currentConfig: ->
config = App.Setting.get('clearbit_config')
if !config
config = {}
if config.organization_autocreate is undefined
config.organization_autocreate = true
if config.organization_shared is undefined
config.organization_shared = false
if !config.user_sync
config.user_sync =
'person.name.givenName': 'user.firstname'
'person.name.familyName': 'user.lastname'
'person.email': 'user.email'
'person.bio': 'user.note'
'company.url': 'user.web'
'person.site': 'user.web'
'company.location': 'user.address'
'person.location': 'user.address'
if !config.organization_sync
config.organization_sync =
'company.legalName': 'organization.name'
'company.name': 'organization.name'
'company.description': 'organization.note'
config
setConfig: (value) ->
App.Setting.set('clearbit_config', value)
render: =>
@config = @currentConfig()
settings = [
{ name: 'api_key', display: 'API Key', tag: 'input', type: 'text', limit: 100, null: false, placeholder: '...', note: 'Your api key.' },
{ name: 'organization_autocreate', display: 'Auto create', tag: 'boolean', type: 'boolean', null: false, note: 'Create organizations automatically if record has one.' },
{ name: 'organization_shared', display: 'Shared', tag: 'boolean', type: 'boolean', null: false, note: 'New organizations are shared.' },
]
@html App.view('integration/clearbit')(
config: @config
settings: settings
)
for setting in settings
setting.display = ''
new App.ControllerForm(
el: @$("[data-name=#{setting.name}]")
model: { configure_attributes: [setting] }
params: @config
)
updateCurrentConfig: =>
config = @config
cleanupInput = @cleanupInput
params = @formParam(@$('form'))
config.api_key = params['api_key']
config.organization_autocreate = params['organization_autocreate']
config.organization_shared = params['organization_shared']
# user sync
config.user_sync = {}
@$('.js-userSync .js-row').each(->
element = $(@)
source = cleanupInput(element.find('input[name="source"]').val())
destination = cleanupInput(element.find('input[name="destination"]').val())
config.user_sync[source] = destination
)
# organization sync
config.organization_sync = {}
@$('.js-organizationSync .js-row').each(->
element = $(@)
source = cleanupInput(element.find('input[name="source"]').val())
destination = cleanupInput(element.find('input[name="destination"]').val())
config.organization_sync[source] = destination
)
@config = config
update: (e) =>
e.preventDefault()
@updateCurrentConfig()
@setConfig(@config)
cleanupInput: (value) ->
return value if !value
value.replace(/\s/g, '').trim()
addUserSync: (e) =>
e.preventDefault()
@updateCurrentConfig()
element = $(e.currentTarget).closest('tr')
source = @cleanupInput(element.find('input[name="source"]').val())
destination = @cleanupInput(element.find('input[name="destination"]').val())
@config.user_sync[source] = destination
@setConfig(@config)
@render()
addOrganizationSync: (e) =>
e.preventDefault()
@updateCurrentConfig()
element = $(e.currentTarget).closest('tr')
source = @cleanupInput(element.find('input[name="source"]').val())
destination = @cleanupInput(element.find('input[name="destination"]').val())
@config.organization_sync[source] = destination
@setConfig(@config)
@render()
removeRow: (e) =>
e.preventDefault()
@updateCurrentConfig()
element = $(e.currentTarget).closest('tr')
element.remove()
class State
@current: ->
App.Setting.get('clearbit_integration')
App.Config.set(
'IntegrationClearbit'
{
name: 'Clearbit'
target: '#system/integration/clearbit'
description: 'A powerfull service to get more information about your customers.'
controller: Index
state: State
}
'NavBarIntegrations'
)

View file

@ -148,7 +148,7 @@ App.Config.set(
{
name: 'sipgate.io'
target: '#system/integration/sipgate'
description: 'VoIP services provide.'
description: 'VoIP service provider with realtime push.'
controller: Index
state: State
}

View file

@ -1,93 +1,3 @@
class App.SettingsForm extends App.Controller
events:
'submit form': 'update'
constructor: ->
super
# check authentication
return if !@authenticate()
@subscribeId = App.Setting.subscribe(@render, initFetch: true, clear: false)
render: =>
# serach area settings
settings = App.Setting.search(
filter:
area: @area
)
# filter online service settings
if App.Config.get('system_online_service')
settings = _.filter(settings, (setting) ->
return if setting.online_service
return if setting.preferences && setting.preferences.online_service_disable
setting
)
return if _.isEmpty(settings)
# sort by prio
settings = _.sortBy( settings, (setting) ->
return if !setting.preferences
setting.preferences.prio
)
localEl = $( App.view('settings/form')(
settings: settings
))
for setting in settings
configure_attributes = setting.options['form']
value = App.Setting.get(setting.name)
params = {}
params[setting.name] = value
new App.ControllerForm(
el: localEl.find("[data-name=#{setting.name}]")
model: { configure_attributes: configure_attributes, className: '' }
params: params
)
@html localEl
update: (e) =>
e.preventDefault()
@formDisable(e)
params = @formParam(e.target)
ui = @
count = 0
for name, value of params
if App.Setting.findByAttribute('name', name)
count += 1
App.Setting.set(
name,
value,
done: ->
ui.formEnable(e)
count -= 1
if count == 0
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent('Update successful!')
timeout: 2000
}
# rerender ui || get new collections and session data
if @preferences
if @preferences.render
App.Event.trigger( 'ui:rerender' )
if @preferences.session_check
App.Auth.loginCheck()
fail: (settings, details) ->
App.Event.trigger 'notify', {
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to update object!')
timeout: 2000
}
)
class App.SettingsArea extends App.Controller
constructor: ->
super
@ -123,9 +33,9 @@ class App.SettingsArea extends App.Controller
elements = []
for setting in settings
if setting.name is 'product_logo'
item = new App.SettingsAreaLogo( setting: setting )
item = new App.SettingsAreaLogo(setting: setting)
else
item = new App.SettingsAreaItem( setting: setting )
item = new App.SettingsAreaItem(setting: setting)
elements.push item.el
@html elements

View file

@ -0,0 +1,89 @@
class App.SettingsForm extends App.Controller
events:
'submit form': 'update'
constructor: ->
super
# check authentication
return if !@authenticate()
@subscribeId = App.Setting.subscribe(@render, initFetch: true, clear: false)
render: =>
# serach area settings
settings = App.Setting.search(
filter:
area: @area
)
# filter online service settings
if App.Config.get('system_online_service')
settings = _.filter(settings, (setting) ->
return if setting.online_service
return if setting.preferences && setting.preferences.online_service_disable
setting
)
return if _.isEmpty(settings)
# sort by prio
settings = _.sortBy( settings, (setting) ->
return if !setting.preferences
setting.preferences.prio
)
localEl = $( App.view('settings/form')(
settings: settings
))
for setting in settings
configure_attributes = setting.options['form']
value = App.Setting.get(setting.name)
params = {}
params[setting.name] = value
new App.ControllerForm(
el: localEl.find("[data-name=#{setting.name}]")
model: { configure_attributes: configure_attributes }
params: params
)
@html localEl
update: (e) =>
e.preventDefault()
@formDisable(e)
params = @formParam(e.target)
ui = @
count = 0
for name, value of params
if App.Setting.findByAttribute('name', name)
count += 1
App.Setting.set(
name,
value,
done: ->
ui.formEnable(e)
count -= 1
if count == 0
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent('Update successful!')
timeout: 2000
}
# rerender ui || get new collections and session data
if @preferences
if @preferences.render
App.Event.trigger( 'ui:rerender' )
if @preferences.session_check
App.Auth.loginCheck()
fail: (settings, details) ->
App.Event.trigger 'notify', {
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to update object!')
timeout: 2000
}
)

View file

@ -220,6 +220,7 @@ class App extends Spine.Controller
# define richtext helper
params.RichText = (string) ->
return string if !string
if string.match(/@T\('/)
string = string.replace(/@T\('(.+?)'\)/g, (match, capture) ->
App.i18n.translateContent(capture)

View file

@ -0,0 +1,75 @@
<form>
<div class="settings-entry">
<table class="settings-list" style="width: 100%;">
<thead>
<tr>
<th width="15%"><%- @T('Title') %>
<th width="50%"><%- @T('Value') %>
<th width="35%"><%- @T('Description') %>
</thead>
<tbody>
<% for setting in @settings: %>
<tr>
<td><%- @T(setting.display) %>
<td data-name="<%- setting.name %>">
<td><p class="help-text"><%- @RichText(setting.note) %></p>
<% end %>
</tbody>
</table>
</div>
<h2><%- @T('Mapping') %></h2>
<p><%- @T('What values of %s should be synced to users.', 'Clearbit') %></p>
<div class="settings-entry">
<table class="settings-list js-userSync" style="width: 100%;">
<thead>
<tr>
<th width="45%"><%- @T('Clearbit') %>
<th width="45%"><%- @T('Zammad') %>
<th width="10%"><%- @T('Action') %>
</thead>
<tbody>
<% for source, destination of @config.user_sync: %>
<tr class="js-row">
<td class="settings-list-control-cell"><input name="source" value="<%= source %>" class="form-control form-control--small js-summary">
<td class="settings-list-control-cell"><input name="destination" value="<%= destination %>" class="form-control form-control--small js-summary">
<td class="settings-list-row-control"><div class="btn btn--text js-remove"><%- @Icon('trash') %> <%- @T('Remove') %></div>
<% end %>
<tr>
<td class="settings-list-control-cell"><input name="source" value="" placeholder="person.attribute" class="form-control form-control--small js-summary">
<td class="settings-list-control-cell"><input name="destination" value="" placeholder="user.attribute" class="form-control form-control--small js-summary">
<td class="settings-list-row-control"><div class="btn btn--text btn--create js-add"><%- @Icon('plus-small') %> <%- @T('Add') %></div>
</tbody>
</table>
</div>
<p><%- @T('What values of %s should be synced to organization.', 'Clearbit') %></p>
<div class="settings-entry">
<table class="settings-list js-organizationSync" style="width: 100%;">
<thead>
<tr>
<th width="45%"><%- @T('Clearbit') %>
<th width="45%"><%- @T('Zammad') %>
<th width="10%"><%- @T('Action') %>
</thead>
<tbody>
<% for source, destination of @config.organization_sync: %>
<tr class="js-row">
<td class="settings-list-control-cell"><input name="source" value="<%= source %>" class="form-control form-control--small js-summary">
<td class="settings-list-control-cell"><input name="destination" value="<%= destination %>" class="form-control form-control--small js-summary">
<td class="settings-list-row-control"><div class="btn btn--text js-remove"><%- @Icon('trash') %> <%- @T('Remove') %></div>
<% end %>
<tr>
<td class="settings-list-control-cell"><input name="source" value="" placeholder="company.attribute" class="form-control form-control--small js-summary">
<td class="settings-list-control-cell"><input name="destination" value="" placeholder="organization.attribute" class="form-control form-control--small js-summary">
<td class="settings-list-row-control"><div class="btn btn--text btn--create js-add"><%- @Icon('plus-small') %> <%- @T('Add') %></div>
</tbody>
</table>
</div>
<button type="submit" class="btn btn--primary"><%- @T('Save') %></button>
</form>

View file

@ -6,7 +6,7 @@
<thead>
<tr>
<th style="width: 30px;"></th>
<th style="width: 40%;"><%- @T('Service') %></th>
<th style="width: 30%;"><%- @T('Service') %></th>
<th><%- @T('Description') %></th>
</tr>
</thead>

View file

@ -0,0 +1,5 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class ExternalSync < ApplicationModel
store :last_payload
end

View file

@ -23,8 +23,13 @@ class Transaction::BackgroundJob
def perform
Setting.where(area: 'Transaction::Backend').order(:name).each {|setting|
backend = Setting.get(setting.name)
integration = Kernel.const_get(backend).new(@item, @params)
integration.perform
begin
integration = Kernel.const_get(backend).new(@item, @params)
integration.perform
rescue => e
logger.error 'ERROR: ' + setting.inspect
logger.error 'ERROR: ' + e.inspect
end
}
end

View file

@ -0,0 +1,321 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Transaction::ClearbitEnrichment
=begin
{
object: 'User',
type: 'create',
object_id: 123,
changes: {
'attribute1' => [before, now],
'attribute2' => [before, now],
}
},
=end
def initialize(item, params = {})
@item = item
@params = params
end
def perform
# return if we run import mode
return if Setting.get('import_mode')
return if @item[:object] != 'User'
return if @item[:type] != 'create'
return if !Setting.get('clearbit_integration')
config = Setting.get('clearbit_config')
return if !config
return if config['api_key'].empty?
user = User.lookup(id: @item[:object_id])
return if !user
Transaction::ClearbitEnrichment.sync_user(user)
end
def self.sync
users = User.of_role('Customer')
users.each {|user|
sync_user(user)
}
end
def self.sync_user(user)
return if !user.email
data = fetch(user.email)
#p 'OO: ' + data.inspect
config = Setting.get('clearbit_config')
return if !config
# get new user sync attributes
user_sync = config['user_sync']
user_sync_values = {}
if user_sync
user_sync.each {|callback, destination|
next if !user_sync_values[destination].empty?
value = _replace(callback, data)
next if !value
user_sync_values[destination] = value
}
end
# get new organization sync attributes
organization_sync = config['organization_sync']
organization_sync_values = {}
if organization_sync
organization_sync.each {|callback, destination|
next if !organization_sync_values[destination].empty?
value = _replace(callback, data)
next if !value
organization_sync_values[destination] = value
}
end
# get latest user synced attributes
external_syn_user = nil
user_sync_values_last_time = {}
if data && data['person'] && data['person']['id']
external_syn_user = ExternalSync.find_by(
source: 'clearbit',
source_id: data['person']['id'],
object: 'User',
o_id: user.id,
)
if external_syn_user && external_syn_user.last_payload
user_sync.each {|callback, destination|
next if !user_sync_values_last_time[destination].empty?
value = _replace(callback, external_syn_user.last_payload)
next if !value
user_sync_values_last_time[destination] = value
}
end
end
# if person record exists
user_has_changed = false
user_sync_values.each {|destination, value|
attribute = destination.sub(/^user\./, '')
next if user[attribute] == value
next if !user[attribute].empty? && user_sync_values_last_time[destination] != user[attribute]
begin
user[attribute] = value
rescue => e
Rails.logger.error "ERROR: Unable to assign user.#{attribute}: #{e.inspect}"
end
user_has_changed = true
}
if user_has_changed
user.updated_by_id = 1
if data['person'] && data['person']['id']
if external_syn_user
external_syn_user.last_payload = data
external_syn_user.save
else
external_syn_user = ExternalSync.create(
source: 'clearbit',
source_id: data['person']['id'],
object: 'User',
o_id: user.id,
last_payload: data,
)
end
end
end
# if no company record exists
if !data['company']
if user_has_changed
user.save
end
Observer::Transaction.commit
return
end
# if company record exists
external_syn_organization = ExternalSync.find_by(
source: 'clearbit',
source_id: data['company']['id'],
)
# create new organization
if !external_syn_organization
# can't create organization without name
if organization_sync_values['organization.name'].empty?
Observer::Transaction.commit
return
end
# find by name
organization = Organization.find_by(name: organization_sync_values['organization.name'])
# create new organization
if !organization
organization = Organization.new(
shared: config['organization_shared'],
updated_by_id: 1,
created_by_id: 1,
)
organization_sync_values.each {|destination, value|
attribute = destination.sub(/^organization\./, '')
next if !organization[attribute].empty?
begin
organization[attribute] = value
rescue => e
Rails.logger.error "ERROR: Unable to assign organization.#{attribute}: #{e.inspect}"
end
}
organization.save
end
ExternalSync.create(
source: 'clearbit',
source_id: data['company']['id'],
object: 'Organization',
o_id: organization.id,
last_payload: data,
)
# assign new organization to user
if !user.organization_id
user.organization_id = organization.id
user.save
end
Observer::Transaction.commit
return
end
# get latest organization synced attributes
organization_sync_values_last_time = {}
if external_syn_organization && external_syn_organization.last_payload
organization_sync.each {|callback, destination|
next if !organization_sync_values_last_time[destination].empty?
value = _replace(callback, external_syn_organization.last_payload)
next if !value
organization_sync_values_last_time[destination] = value
}
end
# update existing organization
organization = Organization.find(external_syn_organization[:o_id])
organization_has_changed = false
organization_sync_values.each {|destination, value|
attribute = destination.sub(/^organization\./, '')
next if organization[attribute] == value
next if !organization[attribute].empty? && organization_sync_values_last_time[destination] != organization[attribute]
begin
organization[attribute] = value
rescue => e
Rails.logger.error "ERROR: Unable to assign organization.#{attribute}: #{e.inspect}"
end
organization_has_changed = true
}
if organization_has_changed
organization.updated_by_id = 1
organization.save
external_syn_organization.last_payload = data
external_syn_organization.save
end
# assign new organization to user
if !user.organization_id
user_has_changed = true
user.organization_id = organization.id
end
if user_has_changed
user.save
end
Observer::Transaction.commit
true
end
def self._replace(callback, data)
object_name = nil
object_method = nil
placeholder = nil
if callback =~ /\A ( [\w]+ )\.( [\w\.]+ ) \z/x
object_name = $1
object_method = $2
end
return if !data
return if !data[object_name]
# do validaton, ignore some methodes
if callback =~ /(`|\.(|\s*)(save|destroy|delete|remove|drop|update\(|update_att|create\(|new|all|where|find))/i
placeholder = "#{callback} (not allowed)"
# get value based on object_name and object_method
elsif object_name && object_method
object_refs = data[object_name]
object_methods = object_method.split('.')
object_methods_s = ''
object_methods.each {|method|
if object_methods_s != ''
object_methods_s += '.'
end
object_methods_s += method
# if method exists
break if !object_refs.respond_to?(method.to_sym) && !object_refs[method]
object_refs = if object_refs.respond_to?(method.to_sym)
object_refs.send(method.to_sym)
else
object_refs[method]
end
}
if object_refs.class == String
placeholder = object_refs
end
end
placeholder
end
def self.fetch(email)
if !Rails.env.production?
filename = "#{Rails.root}/test/fixtures/clearbit/#{email}.json"
if File.exist?(filename)
data = IO.binread(filename)
return JSON.parse(data) if data
end
end
config = Setting.get('clearbit_config')
return if !config
return if config['api_key'].empty?
record = {
direction: 'out',
facility: 'clearbit',
url: "clearbit -> #{email}",
status: 200,
ip: nil,
request: { content: email },
response: {},
method: 'GET',
}
begin
Clearbit.key = config['api_key']
result = Clearbit::Enrichment.find(email: email, stream: true)
record[:response] = { code: 200, content: result.to_s }
rescue => e
record[:status] = 500
record[:response] = { code: 500, content: e.inspect }
end
HttpLog.create(record)
result
end
end

View file

@ -0,0 +1,15 @@
class CreateExternalSync < ActiveRecord::Migration
def up
create_table :external_syncs do |t|
t.string :source, limit: 100, null: false
t.string :source_id, limit: 200, null: false
t.string :object, limit: 100, null: false
t.integer :o_id, null: false
t.text :last_payload, limit: 500.kilobytes + 1, null: true
t.timestamps null: false
end
add_index :external_syncs, [:source, :source_id], unique: true
add_index :external_syncs, [:source, :source_id, :object, :o_id]
add_index :external_syncs, [:object, :o_id]
end
end

View file

@ -0,0 +1,46 @@
class AddClearbitIntegration < ActiveRecord::Migration
def up
Setting.create_if_not_exists(
title: 'Clearbit integration',
name: 'clearbit_integration',
area: 'Integration::Switch',
description: 'Define if Clearbit (http://www.clearbit.com) is enabled or not.',
options: {
form: [
{
display: '',
null: true,
name: 'clearbit_integration',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
preferences: { prio: 1 },
frontend: false
)
Setting.create_if_not_exists(
title: 'Clearbit config',
name: 'clearbit_config',
area: 'Integration::Clearbit',
description: 'Define the Clearbit config.',
options: {},
state: {},
frontend: false,
preferences: { prio: 2 },
)
Setting.create_if_not_exists(
title: 'Define transaction backend.',
name: '9000_clearbit_enrichment',
area: 'Transaction::Backend',
description: 'Define the transaction backend which will enrich customer and organization informations from (http://www.clearbit.com).',
options: {},
state: 'Transaction::ClearbitEnrichment',
frontend: false
)
end
end

View file

@ -1864,6 +1864,48 @@ Setting.create_if_not_exists(
frontend: false,
preferences: { prio: 2 },
)
Setting.create_if_not_exists(
title: 'Clearbit integration',
name: 'clearbit_integration',
area: 'Integration::Switch',
description: 'Define if Clearbit (http://www.clearbit.com) is enabled or not.',
options: {
form: [
{
display: '',
null: true,
name: 'clearbit_integration',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
preferences: { prio: 1 },
frontend: false
)
Setting.create_if_not_exists(
title: 'Clearbit config',
name: 'clearbit_config',
area: 'Integration::Clearbit',
description: 'Define the Clearbit config.',
options: {},
state: {},
frontend: false,
preferences: { prio: 2 },
)
Setting.create_if_not_exists(
title: 'Define transaction backend.',
name: '9000_clearbit_enrichment',
area: 'Transaction::Backend',
description: 'Define the transaction backend which will enrich customer and organization informations from (http://www.clearbit.com).',
options: {},
state: 'Transaction::ClearbitEnrichment',
frontend: false
)
signature = Signature.create_if_not_exists(
id: 1,

View file

@ -0,0 +1,188 @@
{
"person": {
"id": "d54c54ad-40be-4305-8a34-0ab44710b90d",
"name": {
"fullName": "Alex MacCaw",
"givenName": "Alex",
"familyName": "MacCaw"
},
"email": "alex@alexmaccaw.com",
"gender": "male",
"location": "San Francisco, CA, US",
"timeZone": "America/Los_Angeles",
"utcOffset": -8,
"geo": {
"city": "San Francisco",
"state": "California",
"stateCode": "CA",
"country": "United States",
"countryCode": "US",
"lat": 37.7749295,
"lng": -122.4194155
},
"bio": "O'Reilly author, software engineer & traveller. Founder of https://clearbit.com",
"site": "http://alexmaccaw.com",
"avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/d54c54ad-40be-4305-8a34-0ab44710b90d",
"employment": {
"domain": "clearbit.com",
"name": "Clearbit",
"title": "Founder and CEO",
"role": "ceo",
"seniority": "executive"
},
"facebook": {
"handle": "amaccaw"
},
"github": {
"handle": "maccman",
"avatar": "https://avatars.githubusercontent.com/u/2142?v=2",
"company": "Clearbit",
"blog": "http://alexmaccaw.com",
"followers": 2932,
"following": 94
},
"twitter": {
"handle": "maccaw",
"id": "2006261",
"bio": "O'Reilly author, software engineer & traveller. Founder of https://clearbit.com",
"followers": 15248,
"following": 1711,
"location": "San Francisco",
"site": "http://alexmaccaw.com",
"avatar": "https://pbs.twimg.com/profile_images/1826201101/297606_10150904890650705_570400704_21211347_1883468370_n.jpeg"
},
"linkedin": {
"handle": "pub/alex-maccaw/78/929/ab5"
},
"googleplus": {
"handle": null
},
"angellist": {
"handle": "maccaw",
"bio": "O'Reilly author, engineer & traveller. Mostly harmless.",
"blog": "http://blog.alexmaccaw.com",
"site": "http://alexmaccaw.com",
"followers": 532,
"avatar": "https://d1qb2nb5cznatu.cloudfront.net/users/403357-medium_jpg?1405661263"
},
"aboutme": {
"handle": "maccaw",
"bio": "Software engineer & traveller. Walker, skier, reader, tennis player, breather, ginger beer drinker, scooterer & generally enjoying things :)",
"avatar": "http://o.aolcdn.com/dims-global/dims/ABOUTME/5/803/408/80/http://d3mod6n032mdiz.cloudfront.net/thumb2/m/a/c/maccaw/maccaw-840x560.jpg"
},
"gravatar": {
"handle": "maccman",
"urls": [
{
"value": "http://alexmaccaw.com",
"title": "Personal Website"
}
],
"avatar": "http://2.gravatar.com/avatar/994909da96d3afaf4daaf54973914b64",
"avatars": [
{
"url": "http://2.gravatar.com/avatar/994909da96d3afaf4daaf54973914b64",
"type": "thumbnail"
}
]
},
"fuzzy": false
},
"company": {
"id": "027b0d40-016c-40ea-8925-a076fa640992",
"name": "Uber",
"legalName": "Uber, Inc.",
"domain": "uber.com",
"domainAliases": [],
"url": "http://uber.com",
"site": {
"url": "http://uber.com",
"title": null,
"h1": null,
"metaDescription": null,
"metaAuthor": null,
"phoneNumbers": [
"+1 877-223-8023"
],
"emailAddresses": [
"team@uber.com"
]
},
"tags": [
"Transportation",
"Design",
"SEO",
"Automotive",
"Real Time",
"Limousines",
"Public Transportation",
"Transport"
],
"description": "Uber is a mobile app connecting passengers with drivers for hire.",
"foundedDate": "2009-03-01",
"location": "1455 Market Street, San Francisco, CA 94103, USA",
"timeZone": "America/Los_Angeles",
"utcOffset": -8,
"geo": {
"streetNumber": "1455",
"streetName": "Market Street",
"subPremise": null,
"city": "San Francisco",
"state": "California",
"stateCode": "CA",
"postalCode": "94103",
"country": "United States",
"countryCode": "US",
"lat": 37.7752315,
"lng": -122.4175567
},
"metrics": {
"raised": 5900000000,
"employees": 3250,
"googleRank": 7,
"alexaUsRank": 649,
"alexaGlobalRank": 1071,
"marketCap": null,
"annualRevenue": null
},
"logo": "https://dqus23xyrtg1i.cloudfront.net/v1/logos/027b0d40-016c-40ea-8925-a076fa640992",
"facebook": {
"handle": "uber.IND"
},
"linkedin": {
"handle": "company/uber.com"
},
"twitter": {
"handle": "uber",
"id": 19103481,
"bio": "Everyone's Private Driver. Question, concern or praise? Tweet at your local community manager here: https://t.co/EUiTjLk0xj",
"followers": 176582,
"following": 330,
"location": "Global",
"site": "http://t.co/PtMbwFTeQA",
"avatar": "https://pbs.twimg.com/profile_images/378800000762572812/91ea09a6535666e18ca3c56f731f67ef_normal.jpeg"
},
"angellist": {
"id": 19163,
"handle": "uber",
"description": "Request a car from any mobile phone via text message, iPhone and Android apps. Within minutes, a professional driver in a sleek black car will arrive curbside. Automatically charged to your credit card on file, tip included.",
"followers": 2650,
"blogUrl": "http://blog.uber.com/"
},
"crunchbase": {
"handle": "uber"
},
"phone": "+1 877-223-8023",
"emailProvider": false,
"type": "private",
"tech": [
"google_analytics",
"double_click",
"mixpanel",
"optimizely",
"typekit_by_adobe",
"nginx",
"google_apps"
]
}
}

View file

@ -0,0 +1,196 @@
{
"person": {
"id": "4db7cfeb-8017-4aac-b4b9-debb6d3142c0",
"name": {
"fullName": "Martini Edenhofer",
"givenName": "Martini",
"familyName": "Edenhofer"
},
"email": "me2@otrs.org",
"gender": null,
"location": "Berlin, Berlin, DE",
"timeZone": "Europe/Berlin",
"utcOffset": 2,
"geo": {
"city": "Berlin",
"state": "Berlin",
"stateCode": "Berlin",
"country": "Germany",
"countryCode": "DE",
"lat": 52.52000659999999,
"lng": 13.404954
},
"bio": "Open Source professional and geek. Also known as OTRS inventor. ;)\r\nEntrepreneur and Advisor for open source people in need.",
"site": "http://edenhofer.de/",
"avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/4db7cfeb-8017-4aac-b4b9-debb6d3142c0",
"employment": {
"domain": "otrs.org",
"name": "OTRS",
"title": "CEO",
"role": null,
"seniority": "executive"
},
"facebook": {
"handle": null
},
"github": {
"handle": null,
"id": null,
"avatar": null,
"company": null,
"blog": null,
"followers": null,
"following": null
},
"twitter": {
"handle": "medenhofer",
"id": 219826253,
"bio": "Open Source professional and geek. Also known as OTRS inventor. ;)\r\nEntrepreneur and Advisor for open source people in need.",
"followers": 215,
"following": 260,
"statuses": 114,
"favorites": 8,
"location": "",
"site": "http://edenhofer.de/",
"avatar": "https://pbs.twimg.com/profile_images/1216362658/DSC_0084-p.jpg"
},
"linkedin": {
"handle": "in/enjoyme"
},
"googleplus": {
"handle": null
},
"aboutme": {
"handle": null,
"bio": null,
"avatar": null
},
"gravatar": {
"handle": "bazzi",
"urls": [
{
"value": "http://edenhofer.de",
"title": "Blog"
},
{
"value": "http://znuny.com",
"title": "Znuny - OTRS related services"
}
],
"avatar": "http://2.gravatar.com/avatar/0e321a416c45d214d1040a7667cb0b54",
"avatars": [
{
"url": "http://2.gravatar.com/avatar/0e321a416c45d214d1040a7667cb0b54",
"type": "thumbnail"
}
]
},
"fuzzy": false
},
"company": {
"id": "2b30663f-f1a4-47a9-b2a9-0817b8d3ae7b",
"name": "OTRS",
"legalName": "OTRS AG",
"domain": "otrs.com",
"domainAliases": [
"otrs.org"
],
"url": "http://otrs.com",
"site": {
"url": "http://otrs.com",
"title": "OTRS Simple Service Management",
"h1": "What is OTRS?",
"metaDescription": "OTRS is an Open Source helpdesk software and an IT Service Management software free of licence costs. Improve your Customer Service Management with OTRS.",
"metaAuthor": null,
"phoneNumbers": [
"+49 6172 681988",
"+1 408-549-1717",
"+49 5255 11689664",
"+49 6032 0355578",
"+49 9421 568181",
"+1 408-512-1748",
"+49 8523 6901503",
"+49 6032 7258038",
"+49 6032 0355568",
"+49 551 141308205"
],
"emailAddresses": [
"sales@otrs.com",
"otrs-demo@otrs.org",
"itsm-demo@otrs.org",
"security@otrs.org",
"investor-relations@otrs.com"
]
},
"category": {
"sector": "Information Technology",
"industryGroup": "Software & Services",
"industry": "Internet Software & Services",
"subIndustry": "Internet Software & Services"
},
"tags": [
"Information Technology & Services",
"Technology",
"Software"
],
"description": "OTRS is an Open Source helpdesk software and an IT Service Management software free of licence costs. Improve your Customer Service Management with OTRS.",
"foundedDate": null,
"location": "Norsk-Data-Straße 1, 61352 Bad Homburg vor der Höhe, Germany",
"timeZone": "Europe/Berlin",
"utcOffset": 2,
"geo": {
"streetNumber": "1",
"streetName": "Norsk-Data-Straße",
"subPremise": null,
"city": "Bad Homburg vor der Höhe",
"postalCode": "61352",
"state": "Hessen",
"stateCode": "HE",
"country": "Germany",
"countryCode": "DE",
"lat": 50.21093,
"lng": 8.652809999999999
},
"logo": "https://logo.clearbit.com/otrs.com",
"facebook": {
"handle": "otrsgroup"
},
"linkedin": {
"handle": "company/otrs-ag"
},
"twitter": {
"handle": "OTRSGroup",
"id": "126673991",
"bio": "OTRS is the leading open source service management software including Help Desk and ITIL V3-certified IT service management (ITSM).",
"followers": 2988,
"following": 2484,
"location": "Cupertino, CA, Bad Homburg",
"site": "http://t.co/F09dcTEScJ",
"avatar": "https://pbs.twimg.com/profile_images/575314188848889856/F4KWmvVX_normal.png"
},
"crunchbase": {
"handle": "organization/otrs"
},
"emailProvider": false,
"type": "private",
"ticker": null,
"phone": null,
"metrics": {
"alexaUsRank": null,
"alexaGlobalRank": 116381,
"googleRank": 0,
"employees": 15,
"marketCap": null,
"raised": null,
"annualRevenue": null
},
"tech": [
"google_analytics",
"double_click",
"google_adwords",
"optimizely",
"wordpress",
"pardot"
]
}
}

View file

@ -0,0 +1,196 @@
{
"person": {
"id": "4db7cfeb-8017-4aac-b4b9-debb6d3142c0",
"name": {
"fullName": "Martin Edenhofer",
"givenName": "Martin",
"familyName": "Edenhofer"
},
"email": "me@otrs.org",
"gender": null,
"location": "Berlin, Berlin, DE",
"timeZone": "Europe/Berlin",
"utcOffset": 2,
"geo": {
"city": "Berlin",
"state": "Berlin",
"stateCode": "Berlin",
"country": "Germany",
"countryCode": "DE",
"lat": 52.52000659999999,
"lng": 13.404954
},
"bio": "Open Source professional and geek. Also known as OTRS inventor. ;)\r\nEntrepreneur and Advisor for open source people in need.",
"site": "http://edenhofer.de/",
"avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/4db7cfeb-8017-4aac-b4b9-debb6d3142c0",
"employment": {
"domain": "otrs.org",
"name": "OTRS",
"title": "CEO",
"role": null,
"seniority": "executive"
},
"facebook": {
"handle": null
},
"github": {
"handle": null,
"id": null,
"avatar": null,
"company": null,
"blog": null,
"followers": null,
"following": null
},
"twitter": {
"handle": "medenhofer",
"id": 219826253,
"bio": "Open Source professional and geek. Also known as OTRS inventor. ;)\r\nEntrepreneur and Advisor for open source people in need.",
"followers": 215,
"following": 260,
"statuses": 114,
"favorites": 8,
"location": "",
"site": "http://edenhofer.de/",
"avatar": "https://pbs.twimg.com/profile_images/1216362658/DSC_0084-p.jpg"
},
"linkedin": {
"handle": "in/enjoyme"
},
"googleplus": {
"handle": null
},
"aboutme": {
"handle": null,
"bio": null,
"avatar": null
},
"gravatar": {
"handle": "bazzi",
"urls": [
{
"value": "http://edenhofer.de",
"title": "Blog"
},
{
"value": "http://znuny.com",
"title": "Znuny - OTRS related services"
}
],
"avatar": "http://2.gravatar.com/avatar/0e321a416c45d214d1040a7667cb0b54",
"avatars": [
{
"url": "http://2.gravatar.com/avatar/0e321a416c45d214d1040a7667cb0b54",
"type": "thumbnail"
}
]
},
"fuzzy": false
},
"company": {
"id": "2b30663f-f1a4-47a9-b2a9-0817b8d3ae7b",
"name": "OTRS",
"legalName": null,
"domain": "otrs.com",
"domainAliases": [
"otrs.org"
],
"url": "http://otrs.com",
"site": {
"url": "http://otrs.com",
"title": "OTRS Simple Service Management",
"h1": "What is OTRS?",
"metaDescription": "OTRS is an Open Source helpdesk software and an IT Service Management software free of licence costs. Improve your Customer Service Management with OTRS.",
"metaAuthor": null,
"phoneNumbers": [
"+49 6172 681988",
"+1 408-549-1717",
"+49 5255 11689664",
"+49 6032 0355578",
"+49 9421 568181",
"+1 408-512-1748",
"+49 8523 6901503",
"+49 6032 7258038",
"+49 6032 0355568",
"+49 551 141308205"
],
"emailAddresses": [
"sales@otrs.com",
"otrs-demo@otrs.org",
"itsm-demo@otrs.org",
"security@otrs.org",
"investor-relations@otrs.com"
]
},
"category": {
"sector": "Information Technology",
"industryGroup": "Software & Services",
"industry": "Internet Software & Services",
"subIndustry": "Internet Software & Services"
},
"tags": [
"Information Technology & Services",
"Technology",
"Software"
],
"description": "OTRS is an Open Source helpdesk software and an IT Service Management software free of licence costs. Improve your Customer Service Management with OTRS.",
"foundedDate": null,
"location": "Norsk-Data-Straße 1, 61352 Bad Homburg vor der Höhe, Germany",
"timeZone": "Europe/Berlin",
"utcOffset": 2,
"geo": {
"streetNumber": "1",
"streetName": "Norsk-Data-Straße",
"subPremise": null,
"city": "Bad Homburg vor der Höhe",
"postalCode": "61352",
"state": "Hessen",
"stateCode": "HE",
"country": "Germany",
"countryCode": "DE",
"lat": 50.21093,
"lng": 8.652809999999999
},
"logo": "https://logo.clearbit.com/otrs.com",
"facebook": {
"handle": "otrsgroup"
},
"linkedin": {
"handle": "company/otrs-ag"
},
"twitter": {
"handle": "OTRSGroup",
"id": "126673991",
"bio": "OTRS is the leading open source service management software including Help Desk and ITIL V3-certified IT service management (ITSM).",
"followers": 2988,
"following": 2484,
"location": "Cupertino, CA, Bad Homburg",
"site": "http://t.co/F09dcTEScJ",
"avatar": "https://pbs.twimg.com/profile_images/575314188848889856/F4KWmvVX_normal.png"
},
"crunchbase": {
"handle": "organization/otrs"
},
"emailProvider": false,
"type": "private",
"ticker": null,
"phone": null,
"metrics": {
"alexaUsRank": null,
"alexaGlobalRank": 116381,
"googleRank": 0,
"employees": 15,
"marketCap": null,
"raised": null,
"annualRevenue": null
},
"tech": [
"google_analytics",
"double_click",
"google_adwords",
"optimizely",
"wordpress",
"pardot"
]
}
}

View file

@ -0,0 +1,96 @@
{
"person": null,
"company": {
"id": "273d8666-9d70-43dc-836b-a47a88293905",
"name": "Znuny / ES for OTRS",
"legalName": null,
"domain": "znuny.com",
"domainAliases": [
"znuny.de"
],
"url": "http://znuny.com",
"site": {
"url": "http://znuny.com",
"title": "Support, Consulting, Development and Training for OTRS - Znuny GmbH",
"h1": "We make OTRS support easy!",
"metaDescription": "OTRS Support, Consulting, Development, Training and Customizing - Znuny GmbH",
"metaAuthor": null,
"phoneNumbers": [
"+49 30 6098541",
"+49 4107 15880339",
"+49 8601 81017925",
"+49 4107 15880186",
"+49 8602 16139061"
],
"emailAddresses": [
"info@znuny.com"
]
},
"category": {
"sector": "Industrials",
"industryGroup": "Commercial & Professional Services",
"industry": "Professional Services",
"subIndustry": "Consulting"
},
"tags": [
"Consulting & Professional Services",
"Corporate & Business",
"Information Technology & Services"
],
"description": "OTRS Support, Consulting, Development, Training and Customizing - Znuny GmbH",
"foundedDate": null,
"location": "Marienstraße 11, 10117 Berlin, Germany",
"timeZone": "Europe/Berlin",
"utcOffset": 2,
"geo": {
"streetNumber": "11",
"streetName": "Marienstraße",
"subPremise": null,
"city": "Berlin",
"postalCode": "10117",
"state": "Berlin",
"stateCode": "Berlin",
"country": "Germany",
"countryCode": "DE",
"lat": 52.52182,
"lng": 13.38268
},
"logo": "https://logo.clearbit.com/znuny.com",
"facebook": {
"handle": null
},
"linkedin": {
"handle": "company/znuny-gmbh"
},
"twitter": {
"handle": "znuny",
"id": "293437546",
"bio": "Enterprise Services for OTRS! We love to do what we can do!",
"followers": 85,
"following": 63,
"location": "Berlin",
"site": "http://t.co/miuzrhoHeG",
"avatar": "https://pbs.twimg.com/profile_images/2460325455/hix7so4b0h0miq9gwkw8_normal.png"
},
"crunchbase": {
"handle": null
},
"emailProvider": false,
"type": "private",
"ticker": null,
"phone": null,
"metrics": {
"alexaUsRank": null,
"alexaGlobalRank": 10086408,
"googleRank": 3,
"employees": null,
"marketCap": null,
"raised": null,
"annualRevenue": null
},
"tech": [
"google_analytics",
"ruby_on_rails"
]
}
}

View file

@ -0,0 +1,120 @@
{
"person": {
"id": "4db7cfeb-8017-4aac-b4b9-debb6d3142c0-1",
"name": {
"fullName": "Bob Smith",
"givenName": "Bob",
"familyName": "Smith"
},
"email": "testing5@znuny.com",
"gender": null,
"location": "Berlin, Berlin, DE",
"timeZone": "Europe/Berlin",
"utcOffset": 2,
"geo": {
"city": "Berlin",
"state": "Berlin",
"stateCode": "Berlin",
"country": "Germany",
"countryCode": "DE",
"lat": 52.52000659999999,
"lng": 13.404954
},
"bio": "some_bio",
"site": "http://example.com/",
"avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/4db7cfeb-8017-4aac-b4b9-debb6d3142c0"
},
"company": {
"id": "273d8666-9d70-43dc-836b-a47a88293905",
"name": "Znuny2",
"legalName": null,
"domain": "znuny.com",
"domainAliases": [
"znuny.de"
],
"url": "http://znuny.com",
"site": {
"url": "http://znuny.com",
"title": "Support, Consulting, Development and Training for OTRS - Znuny GmbH",
"h1": "We make OTRS support easy!",
"metaDescription": "OTRS Support, Consulting, Development, Training and Customizing - Znuny GmbH",
"metaAuthor": null,
"phoneNumbers": [
"+49 30 6098541",
"+49 4107 15880339",
"+49 8601 81017925",
"+49 4107 15880186",
"+49 8602 16139061"
],
"emailAddresses": [
"info@znuny.com"
]
},
"category": {
"sector": "Industrials",
"industryGroup": "Commercial & Professional Services",
"industry": "Professional Services",
"subIndustry": "Consulting"
},
"tags": [
"Consulting & Professional Services",
"Corporate & Business",
"Information Technology & Services"
],
"description": "Znuny2 GmbH",
"foundedDate": null,
"location": "Marienstraße 11, 10117 Berlin, Germany",
"timeZone": "Europe/Berlin",
"utcOffset": 2,
"geo": {
"streetNumber": "11",
"streetName": "Marienstraße",
"subPremise": null,
"city": "Berlin",
"postalCode": "10117",
"state": "Berlin",
"stateCode": "Berlin",
"country": "Germany",
"countryCode": "DE",
"lat": 52.52182,
"lng": 13.38268
},
"logo": "https://logo.clearbit.com/znuny.com",
"facebook": {
"handle": null
},
"linkedin": {
"handle": "company/znuny-gmbh"
},
"twitter": {
"handle": "znuny",
"id": "293437546",
"bio": "Enterprise Services for OTRS! We love to do what we can do!",
"followers": 85,
"following": 63,
"location": "Berlin",
"site": "http://t.co/miuzrhoHeG",
"avatar": "https://pbs.twimg.com/profile_images/2460325455/hix7so4b0h0miq9gwkw8_normal.png"
},
"crunchbase": {
"handle": null
},
"emailProvider": false,
"type": "private",
"ticker": null,
"phone": null,
"metrics": {
"alexaUsRank": null,
"alexaGlobalRank": 10086408,
"googleRank": 3,
"employees": null,
"marketCap": null,
"raised": null,
"annualRevenue": null
},
"tech": [
"google_analytics",
"ruby_on_rails"
]
}
}

View file

@ -0,0 +1,281 @@
# encoding: utf-8
require 'integration_test_helper'
class ClearbitTest < ActiveSupport::TestCase
# check
test 'base' do
if !ENV['CLEARBIT_CI_API_KEY']
raise "ERROR: Need CLEARBIT_CI_API_KEY - hint CLEARBIT_CI_API_KEY='abc...'"
end
# set system mode to done / to activate
Setting.set('system_init_done', true)
Setting.set('clearbit_integration', true)
Setting.set('clearbit_config', {
api_key: ENV['CLEARBIT_CI_API_KEY'],
organization_autocreate: true,
organization_shared: false,
user_sync: {
'person.name.givenName' => 'user.firstname',
'person.name.familyName' => 'user.lastname',
'person.email' => 'user.email',
'person.bio' => 'user.note',
'company.url' => 'user.web',
'person.site' => 'user.web',
'company.location' => 'user.address',
'person.location' => 'user.address',
#'person.timeZone' => 'user.preferences[:timezone]',
#'person.gender' => 'user.preferences[:gender]',
},
organization_sync: {
'company.legalName' => 'organization.name',
'company.name' => 'organization.name',
'company.description' => 'organization.note',
},
})
# case 1 - person + company (demo data set)
customer1 = User.create(
firstname: '',
lastname: 'Should be still there',
email: 'alex@alexmaccaw.com',
note: '',
updated_by_id: 1,
created_by_id: 1,
)
assert(customer1)
Observer::Transaction.commit
Delayed::Worker.new.work_off
assert(ExternalSync.find_by(source: 'clearbit', object: 'User', o_id: customer1.id))
customer1_lookup = User.lookup(id: customer1.id)
assert_equal('Alex', customer1_lookup.firstname)
assert_equal('Should be still there', customer1_lookup.lastname)
assert_equal('O\'Reilly author, software engineer & traveller. Founder of https://clearbit.com', customer1_lookup.note)
assert_equal('1455 Market Street, San Francisco, CA 94103, USA', customer1_lookup.address)
organization1_lookup = Organization.find_by(name: 'Uber, Inc.')
assert(ExternalSync.find_by(source: 'clearbit', object: 'Organization', o_id: organization1_lookup.id))
assert_equal(false, organization1_lookup.shared)
assert_equal('Uber is a mobile app connecting passengers with drivers for hire.', organization1_lookup.note)
# case 2 - person + company
customer2 = User.create(
firstname: '',
lastname: '',
email: 'me@example.com',
note: '',
updated_by_id: 1,
created_by_id: 1,
)
assert(customer2)
Observer::Transaction.commit
Delayed::Worker.new.work_off
assert(ExternalSync.find_by(source: 'clearbit', object: 'User', o_id: customer2.id))
customer2_lookup = User.lookup(id: customer2.id)
assert_equal('Martin', customer2_lookup.firstname)
assert_equal('Edenhofer', customer2_lookup.lastname)
assert_equal("Open Source professional and geek. Also known as OTRS inventor. ;)\r\nEntrepreneur and Advisor for open source people in need.", customer2_lookup.note)
assert_equal('Norsk-Data-Straße 1, 61352 Bad Homburg vor der Höhe, Germany', customer2_lookup.address)
organization2_lookup = Organization.find_by(name: 'OTRS')
assert(ExternalSync.find_by(source: 'clearbit', object: 'Organization', o_id: organization2_lookup.id))
assert_equal(false, organization2_lookup.shared)
assert_equal('OTRS is an Open Source helpdesk software and an IT Service Management software free of licence costs. Improve your Customer Service Management with OTRS.', organization2_lookup.note)
# update with own values (do not overwrite)
customer2.update_attributes(
firstname: 'Martini',
note: 'changed by my self',
)
Observer::Transaction.commit
Delayed::Worker.new.work_off
assert(ExternalSync.find_by(source: 'clearbit', object: 'User', o_id: customer2.id))
customer2_lookup = User.lookup(id: customer2.id)
assert_equal('Martini', customer2_lookup.firstname)
assert_equal('Edenhofer', customer2_lookup.lastname)
assert_equal('changed by my self', customer2_lookup.note)
assert_equal('Norsk-Data-Straße 1, 61352 Bad Homburg vor der Höhe, Germany', customer2_lookup.address)
Transaction::ClearbitEnrichment.sync_user(customer2)
Delayed::Worker.new.work_off
customer2_lookup = User.lookup(id: customer2.id)
assert_equal('Martini', customer2_lookup.firstname)
assert_equal('Edenhofer', customer2_lookup.lastname)
assert_equal('changed by my self', customer2_lookup.note)
assert_equal('Norsk-Data-Straße 1, 61352 Bad Homburg vor der Höhe, Germany', customer2_lookup.address)
# update with own values (do not overwrite)
customer2.update_attributes(
firstname: '',
note: 'changed by my self',
)
Transaction::ClearbitEnrichment.sync_user(customer2)
Delayed::Worker.new.work_off
customer2_lookup = User.lookup(id: customer2.id)
assert_equal('Martin', customer2_lookup.firstname)
assert_equal('Edenhofer', customer2_lookup.lastname)
assert_equal('changed by my self', customer2_lookup.note)
assert_equal('Norsk-Data-Straße 1, 61352 Bad Homburg vor der Höhe, Germany', customer2_lookup.address)
# update with changed values at clearbit site (do overwrite)
customer2.update_attributes(
email: 'me2@example.com',
)
Transaction::ClearbitEnrichment.sync_user(customer2)
Delayed::Worker.new.work_off
customer2_lookup = User.lookup(id: customer2.id)
assert_equal('Martini', customer2_lookup.firstname)
assert_equal('Edenhofer', customer2_lookup.lastname)
assert_equal('changed by my self', customer2_lookup.note)
assert_equal('Norsk-Data-Straße 1, 61352 Bad Homburg vor der Höhe, Germany', customer2_lookup.address)
organization2_lookup = Organization.find_by(name: 'OTRS AG')
assert(ExternalSync.find_by(source: 'clearbit', object: 'Organization', o_id: organization2_lookup.id))
assert_equal(false, organization2_lookup.shared)
assert_equal('OTRS is an Open Source helpdesk software and an IT Service Management software free of licence costs. Improve your Customer Service Management with OTRS.', organization2_lookup.note)
# case 3 - no person
customer3 = User.create(
firstname: '',
lastname: '',
email: 'testing4@znuny.com',
note: '',
updated_by_id: 1,
created_by_id: 1,
)
assert(customer3)
Observer::Transaction.commit
Delayed::Worker.new.work_off
assert_not(ExternalSync.find_by(source: 'clearbit', object: 'User', o_id: customer3.id))
customer3_lookup = User.lookup(id: customer3.id)
assert_not_equal(customer3.updated_at, customer3_lookup.updated_at)
assert_equal('', customer3_lookup.firstname)
assert_equal('', customer3_lookup.lastname)
assert_equal('', customer3_lookup.note)
assert_equal('http://znuny.com', customer3_lookup.web)
assert_equal('Marienstraße 11, 10117 Berlin, Germany', customer3_lookup.address)
organization3_lookup = Organization.find_by(name: 'Znuny / ES for OTRS')
assert(ExternalSync.find_by(source: 'clearbit', object: 'Organization', o_id: organization3_lookup.id))
assert_equal(false, organization3_lookup.shared)
assert_equal('OTRS Support, Consulting, Development, Training and Customizing - Znuny GmbH', organization3_lookup.note)
# case 4 - no person / real api call
customer4 = User.create(
firstname: '',
lastname: '',
email: 'testing5@clearbit.com',
note: '',
updated_by_id: 1,
created_by_id: 1,
)
assert(customer4)
Observer::Transaction.commit
Delayed::Worker.new.work_off
assert_not(ExternalSync.find_by(source: 'clearbit', object: 'User', o_id: customer4.id))
customer4_lookup = User.lookup(id: customer4.id)
assert_not_equal(customer4.updated_at, customer4_lookup.updated_at)
assert_equal('', customer4_lookup.firstname)
assert_equal('', customer4_lookup.lastname)
assert_equal('', customer4_lookup.note)
assert_equal('http://clearbit.com', customer4_lookup.web)
assert_equal('', customer4_lookup.address)
organization4_lookup = Organization.find_by(name: 'Clearbit')
assert(ExternalSync.find_by(source: 'clearbit', object: 'Organization', o_id: organization4_lookup.id))
assert_equal(false, organization4_lookup.shared)
assert_equal('Clearbit provides powerful products and data APIs to help your business grow. Contact enrichment, lead generation, financial compliance, and more...', organization4_lookup.note)
end
# check
test 'base with invalid input' do
if !ENV['CLEARBIT_CI_API_KEY']
raise "ERROR: Need CLEARBIT_CI_API_KEY - hint CLEARBIT_CI_API_KEY='abc...'"
end
# set system mode to done / to activate
Setting.set('system_init_done', true)
Setting.set('clearbit_integration', true)
Setting.set('clearbit_config', {
api_key: ENV['CLEARBIT_CI_API_KEY'],
organization_autocreate: true,
organization_shared: true,
user_sync: {
'person.name.givenName' => 'user.firstname',
'person.name.familyName' => 'user.lastname',
'person.email' => 'user.email',
'person.bio' => 'user.note_not_existing',
'company.url' => 'user.web',
'person.site' => 'user.web',
'company.location' => 'user.address',
'person.location' => 'user.address',
},
organization_sync: {
'company.legalName' => 'organization.name',
'company.name' => 'organization.name',
'company.description' => 'organization.note_not_existing',
},
})
# case 1 - person + company (demo data set)
customer1 = User.create(
firstname: '',
lastname: 'Should be still there',
email: 'testing5@znuny.com',
note: '',
updated_by_id: 1,
created_by_id: 1,
)
assert(customer1)
Observer::Transaction.commit
Delayed::Worker.new.work_off
assert(ExternalSync.find_by(source: 'clearbit', object: 'User', o_id: customer1.id))
customer1_lookup = User.lookup(id: customer1.id)
assert_equal('Bob', customer1_lookup.firstname)
assert_equal('Should be still there', customer1_lookup.lastname)
assert_equal('', customer1_lookup.note)
assert_equal('Marienstraße 11, 10117 Berlin, Germany', customer1_lookup.address)
organization1_lookup = Organization.find_by(name: 'Znuny2')
assert(ExternalSync.find_by(source: 'clearbit', object: 'Organization', o_id: organization1_lookup.id))
assert_equal(true, organization1_lookup.shared)
assert_equal('', organization1_lookup.note)
end
end