gooddata_marketo 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +131 -0
- data/README.md +207 -0
- data/bin/Gemfile +10 -0
- data/bin/auth.json +17 -0
- data/bin/main.rb +0 -0
- data/bin/process.rbx +541 -0
- data/examples/all_lead_changes.rb +119 -0
- data/examples/all_leads.rb +249 -0
- data/examples/lead_changes_to_ads.rb +63 -0
- data/gooddata_marketo.gemspec +24 -0
- data/gooddata_marketo_gem.zip +0 -0
- data/lib/gooddata_marketo.rb +24 -0
- data/lib/gooddata_marketo/adapters/rest.rb +287 -0
- data/lib/gooddata_marketo/client.rb +373 -0
- data/lib/gooddata_marketo/data/activity_types.rb +104 -0
- data/lib/gooddata_marketo/data/reserved_sql_keywords.rb +205 -0
- data/lib/gooddata_marketo/helpers/s3.rb +141 -0
- data/lib/gooddata_marketo/helpers/stringwizard.rb +32 -0
- data/lib/gooddata_marketo/helpers/table.rb +323 -0
- data/lib/gooddata_marketo/helpers/webdav.rb +118 -0
- data/lib/gooddata_marketo/loads.rb +235 -0
- data/lib/gooddata_marketo/models/campaigns.rb +57 -0
- data/lib/gooddata_marketo/models/channels.rb +30 -0
- data/lib/gooddata_marketo/models/child/activity.rb +104 -0
- data/lib/gooddata_marketo/models/child/criteria.rb +17 -0
- data/lib/gooddata_marketo/models/child/lead.rb +118 -0
- data/lib/gooddata_marketo/models/child/mobj.rb +68 -0
- data/lib/gooddata_marketo/models/etl.rb +75 -0
- data/lib/gooddata_marketo/models/leads.rb +493 -0
- data/lib/gooddata_marketo/models/load.rb +17 -0
- data/lib/gooddata_marketo/models/mobjects.rb +121 -0
- data/lib/gooddata_marketo/models/streams.rb +137 -0
- data/lib/gooddata_marketo/models/tags.rb +35 -0
- data/lib/gooddata_marketo/models/validate.rb +46 -0
- metadata +177 -0
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module GoodDataMarketo
|
4
|
+
VERSION = "0.0.1"
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
attr_accessor :logging
|
9
|
+
|
10
|
+
def client(config = {})
|
11
|
+
GoodDataMarketo.logging = false
|
12
|
+
GoodDataMarketo::Client.new(config)
|
13
|
+
end
|
14
|
+
|
15
|
+
def freeze(*args) # Bloc freeze args.
|
16
|
+
args.each(&:freeze).freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
alias :connect :client
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'gooddata_marketo/client'
|
@@ -0,0 +1,287 @@
|
|
1
|
+
require 'gooddata_marketo/models/child/lead'
|
2
|
+
|
3
|
+
require 'rest_client'
|
4
|
+
require 'json'
|
5
|
+
require 'csv'
|
6
|
+
|
7
|
+
class GoodDataMarketo::RESTAdapter
|
8
|
+
|
9
|
+
attr_accessor :token
|
10
|
+
attr_accessor :token_timer
|
11
|
+
|
12
|
+
def initialize config = {}
|
13
|
+
|
14
|
+
@api_limit = MARKETO_API_LIMIT
|
15
|
+
@lead_list_dump = config[:file] || LEAD_LIST_DUMP_CSV || 'marketo_leads_dump.csv'
|
16
|
+
@marketo_subdomain = config[:subdomain] || MARKETO_SUBDOMAIN
|
17
|
+
@marketo_rest_secret = config[:secret] || config[:user] || MARKETO_REST_SECRET
|
18
|
+
@marketo_rest_id = config[:id] || config[:user] || MARKETO_REST_ID
|
19
|
+
@marketo_domain = "https://#{@marketo_subdomain}.mktorest.com"
|
20
|
+
@webdav = config[:webdav]
|
21
|
+
@lead_list_ids = []
|
22
|
+
@token = self.get_token unless config[:token]
|
23
|
+
@token_uri = "?access_token=#{@token}"
|
24
|
+
|
25
|
+
# Example endpoint = "/rest/v1/lists.json"
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
# If token has existed for more than 6000 seconds, refresh it.
|
30
|
+
def refresh_token?
|
31
|
+
if (@token_timer + 6000) < Time.now
|
32
|
+
self.get_token
|
33
|
+
true
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def get url
|
40
|
+
@api_limit -= 1
|
41
|
+
begin
|
42
|
+
puts "#{Time.now} => REST:GET (#{url})" if GoodDataMarketo.logging
|
43
|
+
response = RestClient.get url
|
44
|
+
rescue Exception => exc
|
45
|
+
puts exc if GoodDataMarketo.logging
|
46
|
+
puts "#{Time.now} => Possible API Limit reached, last request was ##{@api_limit} of #{MARKETO_API_LIMIT}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_lead_lists next_page_token = nil
|
51
|
+
|
52
|
+
endpoint = "/rest/v1/lists.json"
|
53
|
+
url = @marketo_domain + endpoint + @token_uri
|
54
|
+
|
55
|
+
if next_page_token
|
56
|
+
endpoint = "/rest/v1/lists.json"
|
57
|
+
url = @marketo_domain + endpoint + @token_uri + "&nextPageToken="+next_page_token
|
58
|
+
end
|
59
|
+
|
60
|
+
response = self.get url
|
61
|
+
|
62
|
+
json = JSON.parse(response.body, :symbolize_names => true)
|
63
|
+
|
64
|
+
json[:result].each { |m| @lead_list_ids << m[:id] }
|
65
|
+
|
66
|
+
next_page_token = json[:nextPageToken]
|
67
|
+
|
68
|
+
if next_page_token
|
69
|
+
self.get_lead_lists next_page_token
|
70
|
+
else
|
71
|
+
@lead_list_ids
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_multiple_leads config = {}
|
77
|
+
|
78
|
+
self.refresh_token?
|
79
|
+
|
80
|
+
ids = config[:ids] || config[:values] || [28567,30885,32240,37161,40832]
|
81
|
+
domain = @marketo_domain
|
82
|
+
parameters = "&filterType=id"+"&filterValues="+ids.join(',')
|
83
|
+
endpoint= "/rest/v1/leads.json"
|
84
|
+
url = domain + endpoint + @token_uri + parameters
|
85
|
+
|
86
|
+
self.get url
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_all_leads config = {}
|
91
|
+
|
92
|
+
self.refresh_token?
|
93
|
+
|
94
|
+
# Check if we already have a leads list, if so, download it.
|
95
|
+
self.load_lists
|
96
|
+
|
97
|
+
# Check if there was a stream broken while downloading a specific list.
|
98
|
+
self.load_last_page
|
99
|
+
|
100
|
+
# Check if there was a partial ID dump available on WebDAV, if so download it..
|
101
|
+
self.load_id_dump
|
102
|
+
|
103
|
+
@fields = config[:fields] || 'id'
|
104
|
+
|
105
|
+
# For each of the lead list ids, download their respective leads by id.
|
106
|
+
@csv = CSV.open(@lead_list_dump,'a+')
|
107
|
+
|
108
|
+
lists = @lead_list_ids
|
109
|
+
|
110
|
+
lists.each do |list|
|
111
|
+
|
112
|
+
id = @lead_list_ids.shift
|
113
|
+
|
114
|
+
domain = @marketo_domain
|
115
|
+
parameters = "&fields=#{@fields}"
|
116
|
+
endpoint= "/rest/v1/list/#{id}/leads.json"
|
117
|
+
url = domain + endpoint + @token_uri + parameters
|
118
|
+
|
119
|
+
# Conditional recursive function ends if nextPageToken is not available in response. Writes results to CSV.
|
120
|
+
def rest_lead_stream url, list_id
|
121
|
+
|
122
|
+
response = self.get url
|
123
|
+
json = JSON.parse(response.body, :symbolize_names => true)
|
124
|
+
results = json[:result]
|
125
|
+
|
126
|
+
if results
|
127
|
+
results.each { |result| @csv << [result[:id]] }
|
128
|
+
@csv.flush
|
129
|
+
puts "#{Time.now} => REST:leadList:#{list_id}:Results:#{results.length}" if GoodDataMarketo.logging
|
130
|
+
end
|
131
|
+
|
132
|
+
next_page_token = json[:nextPageToken]
|
133
|
+
|
134
|
+
# If there is another page, remember it and then attempt the next load.
|
135
|
+
if next_page_token
|
136
|
+
|
137
|
+
self.remember_next_page :token => token, :list => list_id
|
138
|
+
domain = @marketo_domain
|
139
|
+
parameters = "&fields=#{@fields}"
|
140
|
+
endpoint= "/rest/v1/list/#{list_id}/leads.json"
|
141
|
+
url = domain + endpoint + @token_uri + parameters + "&nextPageToken=" + next_page_token
|
142
|
+
rest_lead_stream url, list_id
|
143
|
+
|
144
|
+
else
|
145
|
+
|
146
|
+
# Update the local and remote lead lists
|
147
|
+
File.open('lead_list_ids.json','w'){ |f| JSON.dump(@lead_list_ids, f) }
|
148
|
+
@webdav.upload('lead_list_ids.json')
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# While on this list, check to see if it failed working on it before and resume where it left off.
|
155
|
+
if @next_page_token_list == list
|
156
|
+
|
157
|
+
puts "#{Time.now} => REST(Resumed):leadList:#{list}:NextPageToken:#{@next_page_token}" if GoodDataMarketo.logging
|
158
|
+
domain = @marketo_domain
|
159
|
+
parameters = "" #"&fields=#{fields}"
|
160
|
+
endpoint= "/rest/v1/list/#{list}/leads.json"
|
161
|
+
url = domain + endpoint + @token_uri + parameters + "&nextPageToken=" + @next_page_token
|
162
|
+
|
163
|
+
rest_lead_stream url, list
|
164
|
+
|
165
|
+
else
|
166
|
+
|
167
|
+
rest_lead_stream url, list
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
# Remove lists from WebDav & Local, upload Marketo Ids Dump to webdav.
|
174
|
+
self.clean
|
175
|
+
|
176
|
+
# Update the etl controller that an update as occured.
|
177
|
+
self.resolve_with_etl_controller
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
def get_all_lead_ids config = {}
|
182
|
+
config[:fields] = 'id'
|
183
|
+
self.get_all_leads config
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_all_lead_emails config = {}
|
187
|
+
config[:fields] = 'email'
|
188
|
+
self.get_all_leads config
|
189
|
+
end
|
190
|
+
|
191
|
+
def load_last_page
|
192
|
+
|
193
|
+
if @webdav.include? 'lead_list_next_page_token.json'
|
194
|
+
next_page_token_json = @webdav.download 'lead_list_next_page_token.json'
|
195
|
+
json = JSON.parse(next_page_token_json)
|
196
|
+
elsif File.exists? 'lead_list_next_page_token.json'
|
197
|
+
json = JSON.parse( IO.read('lead_list_next_page_token.json'))
|
198
|
+
else
|
199
|
+
json = {}
|
200
|
+
end
|
201
|
+
|
202
|
+
@next_page_token = json[:token]
|
203
|
+
@next_page_token_list = json[:list]
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
def load_id_dump
|
208
|
+
# Check if the lists leads have already been dumped. Append to it.
|
209
|
+
if @webdav.exists? @lead_list_dump
|
210
|
+
file = @webdav.download @lead_list_dump
|
211
|
+
puts "#{Time.now} => WEBDAV:ID_DUMP:Load" if GoodDataMarketo.logging
|
212
|
+
f = File.open(@lead_list_dump,'w')
|
213
|
+
f.write(file)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def load_lists
|
218
|
+
if @webdav.include? 'lead_list_ids.json'
|
219
|
+
lists = @webdav.download 'lead_list_ids.json'
|
220
|
+
@lead_list_ids = JSON.parse(lists)
|
221
|
+
puts "#{Time.now} => WEBDAV:ListsLoaded:#{@lead_list_ids.length}:lead_list_ids.json" if GoodDataMarketo.logging
|
222
|
+
else
|
223
|
+
self.get_lead_lists
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def remember_next_page config = {}
|
228
|
+
File.open('lead_list_next_page_token.json','w'){ |f| JSON.dump(config, f) }
|
229
|
+
@webdav.upload('lead_list_next_page_token.json')
|
230
|
+
end
|
231
|
+
|
232
|
+
def clean
|
233
|
+
|
234
|
+
lli = 'lead_list_ids.json'
|
235
|
+
llnpt = 'lead_list_next_page_token.json'
|
236
|
+
|
237
|
+
# Remove list ids from webdav and local
|
238
|
+
if @webdav.exists?(lli)
|
239
|
+
@webdav.delete(lli)
|
240
|
+
end
|
241
|
+
|
242
|
+
if @webdav.exists?(llnpt)
|
243
|
+
@webdav.delete(llnpt)
|
244
|
+
end
|
245
|
+
|
246
|
+
File.delete(lli) if File.exists? lli
|
247
|
+
File.delete(llnpt) if File.exists? llnpt
|
248
|
+
|
249
|
+
# Upload marketo_dump to webdav for backup.
|
250
|
+
@webdav.upload(@lead_list_dump)
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
def get_token
|
255
|
+
|
256
|
+
|
257
|
+
domain = @marketo_domain
|
258
|
+
endpoint = "/identity/oauth/token?grant_type=client_credentials"
|
259
|
+
url = domain + endpoint + "&client_id=" + @marketo_rest_id + "&client_secret=" + @marketo_rest_secret
|
260
|
+
response = self.get url
|
261
|
+
results = JSON.parse(response.body)
|
262
|
+
access_token = results["access_token"]
|
263
|
+
@token_timer = Time.now
|
264
|
+
@token = access_token
|
265
|
+
access_token
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
def usage
|
270
|
+
domain = @marketo_domain
|
271
|
+
endpoint = "/rest/v1/stats/usage.json"
|
272
|
+
url = domain + endpoint + @token_uri
|
273
|
+
|
274
|
+
# Note this is the only rest call which does not use the log so as not to print the keys to log.
|
275
|
+
response = RestClient.get url
|
276
|
+
|
277
|
+
#Parse reponse and return only access token
|
278
|
+
results = JSON.parse(response.body)['result']
|
279
|
+
end
|
280
|
+
|
281
|
+
def resolve_with_etl_controller
|
282
|
+
|
283
|
+
puts 'Complete'
|
284
|
+
# Here it would update the log that a full upload as occured.
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
@@ -0,0 +1,373 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
5
|
+
|
6
|
+
dependencies = ['aws-sdk -v 1.61.0',
|
7
|
+
'savon -v 2.8.0',
|
8
|
+
'rubyntlm -v 0.3.2',
|
9
|
+
'gooddata -v 0.6.11',
|
10
|
+
'rest-client -v 1.7.2',
|
11
|
+
'pmap -v 1.0.2']
|
12
|
+
|
13
|
+
puts "#{Time.now} => CheckDependencies: #{dependencies.join(', ')}" if GoodDataMarketo.logging
|
14
|
+
dependencies.each do |dep|
|
15
|
+
begin
|
16
|
+
gem dep.split(' ').first
|
17
|
+
rescue LoadError
|
18
|
+
puts "Installing dependency #{dep}..."
|
19
|
+
system("gem install #{dep}")
|
20
|
+
Gem.clear_paths
|
21
|
+
next
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'openssl'
|
26
|
+
require 'savon'
|
27
|
+
require 'json'
|
28
|
+
require 'timeout'
|
29
|
+
require 'date'
|
30
|
+
require 'aws-sdk'
|
31
|
+
require 'pmap'
|
32
|
+
require 'gooddata'
|
33
|
+
require 'gooddata_datawarehouse'
|
34
|
+
|
35
|
+
require 'gooddata_marketo/loads'
|
36
|
+
require 'gooddata_marketo/helpers/stringwizard'
|
37
|
+
require 'gooddata_marketo/helpers/table'
|
38
|
+
require 'gooddata_marketo/helpers/webdav'
|
39
|
+
require 'gooddata_marketo/helpers/s3'
|
40
|
+
|
41
|
+
require 'gooddata_marketo/models/leads'
|
42
|
+
require 'gooddata_marketo/models/validate'
|
43
|
+
require 'gooddata_marketo/models/campaigns'
|
44
|
+
require 'gooddata_marketo/models/channels'
|
45
|
+
require 'gooddata_marketo/models/mobjects'
|
46
|
+
require 'gooddata_marketo/models/streams'
|
47
|
+
require 'gooddata_marketo/models/tags'
|
48
|
+
|
49
|
+
require 'gooddata_marketo/adapters/rest'
|
50
|
+
|
51
|
+
require 'gooddata_marketo/data/activity_types'
|
52
|
+
require 'gooddata_marketo/data/reserved_sql_keywords'
|
53
|
+
|
54
|
+
ensure
|
55
|
+
$VERBOSE = verbose
|
56
|
+
end
|
57
|
+
|
58
|
+
class GoodDataMarketo::Client
|
59
|
+
|
60
|
+
DEFAULT_CONFIG = {
|
61
|
+
wsdl: 'http://app.marketo.com/soap/mktows/2_4?WSDL',
|
62
|
+
read_timeout: 500,
|
63
|
+
open_timeout: 500,
|
64
|
+
namespace_identifier: :ns1,
|
65
|
+
env_namespace: 'SOAP-ENV',
|
66
|
+
namespaces: { 'xmlns:ns1' => 'http://www.marketo.com/mktows/' },
|
67
|
+
pretty_print_xml: true,
|
68
|
+
api_subdomain: '363-IXI-287',
|
69
|
+
api_version: '2_7',
|
70
|
+
log: false,
|
71
|
+
log_level: :debug
|
72
|
+
}
|
73
|
+
|
74
|
+
attr_accessor :load
|
75
|
+
attr_accessor :webdav
|
76
|
+
attr_accessor :api_limit
|
77
|
+
attr_accessor :activity_types
|
78
|
+
|
79
|
+
def initialize(config = {})
|
80
|
+
|
81
|
+
GoodDataMarketo.logging = true if config[:log]
|
82
|
+
|
83
|
+
@api_limit = config[:api_limit] || MARKETO_API_LIMIT
|
84
|
+
|
85
|
+
@loads = nil # Default is no jobs will be active.
|
86
|
+
@load = nil # No job is currently set.
|
87
|
+
@leads = nil
|
88
|
+
|
89
|
+
config = DEFAULT_CONFIG.merge(config)
|
90
|
+
|
91
|
+
@api_version = config.delete(:api_version).freeze
|
92
|
+
@subdomain = config.delete(:api_subdomain).freeze
|
93
|
+
@webdav = config.delete(:webdav)
|
94
|
+
@logger = config.delete(:logger)
|
95
|
+
|
96
|
+
@activity_types = ActivityTypes.new.values
|
97
|
+
|
98
|
+
user_id = config.delete(:user_id)
|
99
|
+
encryption_key = config.delete(:encryption_key)
|
100
|
+
|
101
|
+
@auth = AuthHeader.new(user_id, encryption_key)
|
102
|
+
|
103
|
+
@wsdl = "http://app.marketo.com/soap/mktows/#{@api_version}?WSDL".freeze
|
104
|
+
@endpoint = "https://#{@subdomain}.mktoapi.com/soap/mktows/#{@api_version}".freeze
|
105
|
+
|
106
|
+
#Create SOAP Header
|
107
|
+
@savon = Savon.client(config.merge(endpoint: @endpoint))
|
108
|
+
|
109
|
+
if GoodDataMarketo.logging
|
110
|
+
puts use = self.usage
|
111
|
+
puts "#{Time.now} => Marketo:SOAP/REST:Used of #{MARKETO_API_LIMIT}"
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_rest
|
118
|
+
puts "#{Time.now} => SETUP: Connected to Marketo REST API:#{@subdomain}" if GoodDataMarketo.logging
|
119
|
+
begin
|
120
|
+
self.usage
|
121
|
+
true
|
122
|
+
rescue
|
123
|
+
false
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_soap
|
128
|
+
puts "#{Time.now} => SETUP: Connected to Marketo SOAP API:#{@subdomain}" if GoodDataMarketo.logging
|
129
|
+
begin
|
130
|
+
self.leads.get_by_email('test@test.com')
|
131
|
+
true
|
132
|
+
rescue
|
133
|
+
false
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def configuration
|
138
|
+
DEFAULT_CONFIG
|
139
|
+
end
|
140
|
+
|
141
|
+
def call(web_method, params, config = {}) #:nodoc:
|
142
|
+
@api_limit -= 1
|
143
|
+
@params = params
|
144
|
+
@timeouts = 0
|
145
|
+
@error = nil
|
146
|
+
|
147
|
+
# If the time limit is up, sect the process to wait
|
148
|
+
if @api_limit < 1
|
149
|
+
|
150
|
+
now = DateTime.now.utc
|
151
|
+
cst = now.in_time_zone('Central Time (US & Canada)')
|
152
|
+
delay = (24 - cst.hours) * 2
|
153
|
+
delay = 1 if delay == 0
|
154
|
+
|
155
|
+
sleep (delay * 60 * 60)
|
156
|
+
puts "#{Time.now} => API_LIMIT:Sleeping: #{delay}"
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
begin
|
161
|
+
|
162
|
+
def timed_call web_method, params, config = {}
|
163
|
+
|
164
|
+
puts "#{Time.now} => API Limit: #{@api_limit}" if GoodDataMarketo.logging
|
165
|
+
puts "#{Time.now} => Call: #{web_method}: #{@params.to_s}" if GoodDataMarketo.logging
|
166
|
+
|
167
|
+
Timeout.timeout(config[:timeout] || 4999) do
|
168
|
+
|
169
|
+
response = @savon.call(
|
170
|
+
web_method,
|
171
|
+
message: params,
|
172
|
+
soap_header: { 'ns1:AuthenticationHeader' => @auth.signature }
|
173
|
+
).to_hash
|
174
|
+
|
175
|
+
# Add control flow to the root call because Marketo API changes for structure for just getLeadActivities
|
176
|
+
if response[:success_get_lead_activity]
|
177
|
+
response[:success_get_lead_activity][:lead_activity_list]
|
178
|
+
else
|
179
|
+
response[response.keys.first][:result]
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
timed_call web_method, @params, config
|
187
|
+
|
188
|
+
rescue Timeout::Error => e
|
189
|
+
@timeouts += 1
|
190
|
+
|
191
|
+
forward_days = config[:forward_days] || 30
|
192
|
+
|
193
|
+
def move_forward_30_days original_time, days
|
194
|
+
smart_time = Date.parse(original_time) + days
|
195
|
+
Time.parse(smart_time.to_s).to_s
|
196
|
+
end
|
197
|
+
|
198
|
+
if @params[:start_position]
|
199
|
+
|
200
|
+
last_created_at = @params[:start_position][:last_created_at]
|
201
|
+
latest_created_at = @params[:start_position][:latest_created_at]
|
202
|
+
oldest_created_at = @params[:start_position][:oldest_created_at]
|
203
|
+
last_updated_at = @params[:start_position][:last_updated_at]
|
204
|
+
|
205
|
+
if oldest_created_at
|
206
|
+
new_time = move_forward_30_days(oldest_created_at, forward_days)
|
207
|
+
@params[:start_position][:oldest_created_at] = new_time
|
208
|
+
elsif last_created_at
|
209
|
+
new_time = move_forward_30_days(last_created_at, forward_days)
|
210
|
+
@params[:start_position][:last_created_at] = new_time
|
211
|
+
elsif latest_created_at
|
212
|
+
new_time = move_forward_30_days(latest_created_at, forward_days)
|
213
|
+
@params[:start_position][:latest_created_at] = new_time
|
214
|
+
elsif last_updated_at
|
215
|
+
new_time = move_forward_30_days(last_updated_at, forward_days)
|
216
|
+
@params[:start_position][:last_updated_at] = new_time
|
217
|
+
else
|
218
|
+
exit
|
219
|
+
end
|
220
|
+
|
221
|
+
puts "#{Time.now} => #{e}:Retrying requested date +#{forward_days} days:attempts:#{@timeouts}/12" if GoodDataMarketo.logging
|
222
|
+
retry unless @timeouts > 12
|
223
|
+
|
224
|
+
else
|
225
|
+
exit
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
rescue Exception => e
|
231
|
+
puts @error = e
|
232
|
+
@logger.log(e) if @logger
|
233
|
+
nil
|
234
|
+
end
|
235
|
+
|
236
|
+
def died(json = nil)
|
237
|
+
|
238
|
+
if json
|
239
|
+
file = File.open('marketo_connector_log.json','wb')
|
240
|
+
file.write(json.to_json)
|
241
|
+
exit
|
242
|
+
else
|
243
|
+
json = File.open('marketo_connector_log.json', 'r')
|
244
|
+
json.to_h
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
def stream(web_method, params, config = {})
|
250
|
+
|
251
|
+
# If the stream is part of a load.
|
252
|
+
|
253
|
+
if self.load
|
254
|
+
"#{Time.now} => Load:#{self.load.json[:type]}:#{self.load.json[:method]}" if GoodDataMarketo.logging
|
255
|
+
end
|
256
|
+
|
257
|
+
puts "#{Time.now} => Stream: #{web_method}: #{params.to_s}" if GoodDataMarketo.logging
|
258
|
+
|
259
|
+
safe = config[:safe] || true
|
260
|
+
@timeouts = 0
|
261
|
+
|
262
|
+
def safe_stream web_method, params, config
|
263
|
+
begin
|
264
|
+
#Timeout.timeout(config[:timeout] || 18000) do
|
265
|
+
GoodDataMarketo::Stream.new web_method, params, :client => self
|
266
|
+
#end
|
267
|
+
rescue Timeout::Error => e
|
268
|
+
@timeouts += 1
|
269
|
+
puts e if GoodDataMarketo.logging
|
270
|
+
params[:timeouts] = @timeouts
|
271
|
+
self.load.log('TIMEOUT') if self.load
|
272
|
+
self.died params
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
if safe
|
278
|
+
safe_stream web_method, params, config
|
279
|
+
else
|
280
|
+
GoodDataMarketo::Stream.new web_method, params, :client => self
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
class AuthHeader #:nodoc:
|
287
|
+
DIGEST = OpenSSL::Digest.new('sha1')
|
288
|
+
private_constant :DIGEST
|
289
|
+
|
290
|
+
def initialize(user_id, encryption_key)
|
291
|
+
if user_id.nil? || encryption_key.nil?
|
292
|
+
raise ArgumentError, ":user_id and :encryption_key required"
|
293
|
+
end
|
294
|
+
|
295
|
+
@user_id = user_id
|
296
|
+
@encryption_key = encryption_key
|
297
|
+
end
|
298
|
+
|
299
|
+
attr_reader :user_id
|
300
|
+
|
301
|
+
# Compute the HMAC signature and return it.
|
302
|
+
def signature
|
303
|
+
time = Time.now
|
304
|
+
{
|
305
|
+
mktowsUserId: user_id,
|
306
|
+
requestTimestamp: time.to_s,
|
307
|
+
requestSignature: hmac(time),
|
308
|
+
}
|
309
|
+
end
|
310
|
+
|
311
|
+
private
|
312
|
+
def hmac(time)
|
313
|
+
OpenSSL::HMAC.hexdigest(
|
314
|
+
DIGEST,
|
315
|
+
@encryption_key,
|
316
|
+
"#{time}#{user_id}"
|
317
|
+
)
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
private_constant :AuthHeader
|
323
|
+
|
324
|
+
def rest
|
325
|
+
GoodDataMarketo::RESTAdapter.new :webdav => @webdav
|
326
|
+
end
|
327
|
+
|
328
|
+
def get_all_leads config = {}
|
329
|
+
rest = GoodDataMarketo::RESTAdapter.new :webdav => @webdav
|
330
|
+
rest.get_all_leads
|
331
|
+
end
|
332
|
+
|
333
|
+
alias :write_all_lead_ids_to_csv :get_all_leads
|
334
|
+
|
335
|
+
def set_load load
|
336
|
+
@load = load
|
337
|
+
end
|
338
|
+
|
339
|
+
def leads # http://developers.marketo.com/documentation/soap/getleadchanges/
|
340
|
+
GoodDataMarketo::Leads.new :client => self
|
341
|
+
end
|
342
|
+
|
343
|
+
def usage(config = {})
|
344
|
+
rest = GoodDataMarketo::RESTAdapter.new :webdav => @webdav
|
345
|
+
rest.usage
|
346
|
+
end
|
347
|
+
|
348
|
+
def campaigns # http://developers.marketo.com/documentation/soap/campaigns/
|
349
|
+
GoodDataMarketo::Campaigns.new :client => self
|
350
|
+
end
|
351
|
+
|
352
|
+
def mobjects # http://developers.marketo.com/documentation/soap/getmobjects/
|
353
|
+
GoodDataMarketo::MObjects.new :client => self
|
354
|
+
end
|
355
|
+
|
356
|
+
def operations
|
357
|
+
@savon.operations
|
358
|
+
end
|
359
|
+
|
360
|
+
def loads(config = {})
|
361
|
+
self.load = true
|
362
|
+
@loads = GoodDataMarketo::Loads.new config
|
363
|
+
end
|
364
|
+
|
365
|
+
def load=(load)
|
366
|
+
@load = load
|
367
|
+
end
|
368
|
+
|
369
|
+
alias :objects :mobjects
|
370
|
+
|
371
|
+
alias :lead :leads
|
372
|
+
|
373
|
+
end
|