gooddata_marketo 0.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +131 -0
  4. data/README.md +207 -0
  5. data/bin/Gemfile +10 -0
  6. data/bin/auth.json +16 -0
  7. data/bin/main.rb +24 -0
  8. data/bin/process.rbx +541 -0
  9. data/examples/all_lead_changes.rb +119 -0
  10. data/examples/all_leads.rb +249 -0
  11. data/examples/lead_changes_to_ads.rb +63 -0
  12. data/gooddata_marketo.gemspec +25 -0
  13. data/lib/gooddata_marketo/adapters/rest.rb +287 -0
  14. data/lib/gooddata_marketo/client.rb +373 -0
  15. data/lib/gooddata_marketo/data/activity_types.rb +104 -0
  16. data/lib/gooddata_marketo/data/reserved_sql_keywords.rb +205 -0
  17. data/lib/gooddata_marketo/helpers/s3.rb +141 -0
  18. data/lib/gooddata_marketo/helpers/stringwizard.rb +32 -0
  19. data/lib/gooddata_marketo/helpers/table.rb +323 -0
  20. data/lib/gooddata_marketo/helpers/webdav.rb +118 -0
  21. data/lib/gooddata_marketo/loads.rb +235 -0
  22. data/lib/gooddata_marketo/models/campaigns.rb +57 -0
  23. data/lib/gooddata_marketo/models/channels.rb +30 -0
  24. data/lib/gooddata_marketo/models/child/activity.rb +104 -0
  25. data/lib/gooddata_marketo/models/child/criteria.rb +17 -0
  26. data/lib/gooddata_marketo/models/child/lead.rb +118 -0
  27. data/lib/gooddata_marketo/models/child/mobj.rb +68 -0
  28. data/lib/gooddata_marketo/models/etl.rb +75 -0
  29. data/lib/gooddata_marketo/models/leads.rb +493 -0
  30. data/lib/gooddata_marketo/models/load.rb +17 -0
  31. data/lib/gooddata_marketo/models/mobjects.rb +121 -0
  32. data/lib/gooddata_marketo/models/streams.rb +137 -0
  33. data/lib/gooddata_marketo/models/tags.rb +35 -0
  34. data/lib/gooddata_marketo/models/validate.rb +46 -0
  35. data/lib/gooddata_marketo.rb +24 -0
  36. data/process.rb +517 -0
  37. metadata +177 -0
@@ -0,0 +1,141 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ class S3Helper
5
+
6
+ attr_accessor :bucket_name
7
+ attr_accessor :bucket
8
+
9
+ def initialize config = {}
10
+
11
+ public_key = config[:public_key]
12
+ private_key = config[:private_key] || config[:secret_key]
13
+ self.bucket_name = config[:bucket] || 'marketo_connector'
14
+
15
+ AWS.config(:access_key_id => public_key, :secret_access_key => private_key)
16
+
17
+ @s3 = AWS::S3::Client.new(region: 'us-east-1')
18
+
19
+ bucket_exists = @s3.list_buckets.include? @bucket_name
20
+
21
+ if bucket_exists == false
22
+ bucket = @s3.create_bucket(:bucket_name => @bucket_name)
23
+ else
24
+ bucket = bucket_exists
25
+ end
26
+
27
+ raise 'ERROR! :public_key, :private_key must be passed for configuration.' unless public_key && private_key
28
+
29
+ end
30
+
31
+ def test
32
+ begin
33
+ self.exists? 'tmp_dumb_file'
34
+ puts "#{Time.now} => SETUP: Connect to AWS S3 Bucket:#{self.bucket_name}...success!" if GoodDataMarketo.logging
35
+ true
36
+ rescue
37
+ false
38
+ end
39
+ end
40
+
41
+ def upload file
42
+ puts "#{Time.now} => Uploading:S3_Bucket#{@bucket_name}: \"#{file}\"" if GoodDataMarketo.logging
43
+ resp = @s3.put_object(
44
+ data: IO.read(file),
45
+ bucket_name: @bucket_name,
46
+ key: file
47
+ )
48
+ end
49
+
50
+ def download file
51
+ begin
52
+ puts "#{Time.now} => Downloading:S3_Bucket#{@bucket_name}: \"#{file}\"" if GoodDataMarketo.logging
53
+ resp = @s3.get_object(bucket_name: @bucket_name, key:file)
54
+ resp[:data]
55
+ rescue
56
+ nil
57
+ end
58
+ end
59
+
60
+ def get_config config = {}
61
+
62
+ file = config[:file] || 'marketo_connector_config.json'
63
+
64
+ if self.exists? file
65
+ json = JSON.parse(self.download(file), :symbolize_names => true)
66
+
67
+ File.open(file,'w'){ |f| JSON.dump(json, f) }
68
+
69
+ self.download(file)
70
+
71
+ json
72
+
73
+ else
74
+
75
+ json = {
76
+ :updated => Time.now.to_s,
77
+ :initial_load_get_multiple => false,
78
+ :initial_load_get_changes => false
79
+ }
80
+
81
+ File.open(file,'w'){ |f| JSON.dump(json, f) }
82
+
83
+ self.upload(file)
84
+
85
+ json
86
+
87
+ end
88
+
89
+ end
90
+
91
+ def set_config config = {}
92
+
93
+ if config[:file]
94
+ file = config.delete(:file)
95
+ else
96
+ file = 'marketo_connector_config.json'
97
+ end
98
+
99
+ if self.exists? file
100
+ json = JSON.parse(self.download(file), :symbolize_names => true)
101
+ else
102
+ json = Hash.new
103
+ end
104
+
105
+ new_json = json.merge(config)
106
+
107
+ new_json[:updated] = Time.now.to_s
108
+
109
+ File.open(file,'w'){ |f| JSON.dump(new_json, f) }
110
+
111
+ self.upload(file)
112
+
113
+ new_json
114
+
115
+ end
116
+
117
+ def latest_config
118
+ if File.exists?('marketo_connector_config.json')
119
+ File.delete('marketo_connector_config.json')
120
+ end
121
+ self.download('marketo_connector_config.json')
122
+ end
123
+
124
+ def exists? file
125
+ begin
126
+ @s3.get_object(bucket_name: @bucket_name, key:file)
127
+ true
128
+ rescue AWS::S3::Errors::NoSuchKey
129
+ false
130
+ end
131
+ end
132
+
133
+ alias :include? :exists?
134
+
135
+ def delete file
136
+ @s3.delete_object(bucket_name: @bucket_name, key: file)
137
+ end
138
+
139
+
140
+ end
141
+
@@ -0,0 +1,32 @@
1
+ require 'date'
2
+
3
+ module StringWizard
4
+ class << self
5
+
6
+ DATE_FORMATS = ['%m/%d/%Y %I:%M:%S %p', '%Y/%m/%d %H:%M:%S', '%d/%m/%Y %H:%M', '%m/%d/%Y', '%Y/%m/%d']
7
+
8
+ def time unparsed_time
9
+ Time.parse(unparsed_time).to_s
10
+ # DATE_FORMATS.each do |format|
11
+ # begin
12
+ # @time_string = Date.strptime(unparsed_time, format)
13
+ # rescue
14
+ # next
15
+ # end
16
+ # end
17
+ #
18
+ # if @time_string.to_s.empty?
19
+ # nil
20
+ # else
21
+ # @time_string.to_s
22
+ # end
23
+
24
+ end
25
+
26
+ def escape_special_characters string
27
+ pattern = /(\'|\*|\-|\\)/
28
+ m = string.gsub(pattern){|match|"" + match}
29
+ m.gsub("\n","")
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,323 @@
1
+ require 'gooddata_marketo/data/reserved_sql_keywords'
2
+
3
+ class Table
4
+
5
+ def initialize config = {}
6
+
7
+ @name_of_table = config[:table] || config[:name]
8
+ @inserts_to_object_count = 0
9
+ @checked_columns_this_insert = false
10
+ @dwh = config[:client]
11
+
12
+ table_exists = @dwh.table_exists? @name_of_table
13
+ raise 'A client is required for this module to initialize (:client => ???)' unless @dwh
14
+
15
+ # Check if the table exists, if not, create one
16
+
17
+ parsed_columns = self.columns_array_to_sql config[:columns]
18
+
19
+ begin
20
+ self.create_table parsed_columns
21
+ rescue
22
+ puts "#{Time.now} => #{@name_of_table} (Table) exists." if GoodDataMarketo.logging
23
+ end
24
+
25
+ end
26
+
27
+ def exists? table=nil
28
+
29
+ if table
30
+ query = table
31
+ else
32
+ query = @name_of_table
33
+ end
34
+
35
+ @dwh.table_exists?(query)
36
+
37
+ end
38
+
39
+ def import_csv file_path
40
+ puts "#{Time.now} => Loading CSV #{file_path} into ADS." if GoodDataMarketo.logging
41
+ begin
42
+ @dwh.load_data_from_csv(@name_of_table, file_path)
43
+ true
44
+ rescue Exception => exp
45
+ puts exp if GoodDataMarketo.logging
46
+ end
47
+
48
+ #@dwh.csv_to_new_table(@name_of_table, file_path)
49
+ end
50
+
51
+ def rename new_name
52
+ query = "ALTER TABLE #{@name_of_table} RENAME TO #{new_name}"
53
+ @dwh.execute(query)
54
+ end
55
+
56
+ def bulk_insert file_path
57
+ loc = Dir.pwd+"/"+file_path
58
+ query = "COPY #{@name_of_table} FROM LOCAL '#{file_path}' DELIMITER ','"
59
+ @dwh.execute(query)
60
+ end
61
+
62
+ def log message
63
+ puts "#{Time.now} => #{message}" if GoodDataMarketo.logging
64
+ message
65
+ end
66
+
67
+ def insert object
68
+
69
+ row = object.to_row.map {|m|
70
+ escaped = m.gsub("'","''")
71
+ m = "'#{escaped}'"
72
+ }
73
+ row[0].to_i
74
+ values = row.join(",")
75
+ columns = self.columns_array_to_string(object.headers)
76
+ self.log query = "INSERT INTO #{@name_of_table} (#{columns}) VALUES (#{values})"
77
+
78
+ tries = 3
79
+ begin
80
+ @dwh.execute(query)
81
+ rescue DataLibraryFailureException => e
82
+ tries -= 1
83
+ if tries > 0
84
+ sleep 3
85
+ retry
86
+ else
87
+ puts e if GoodDataMarketo.logging
88
+ end
89
+ end
90
+
91
+ @checked_columns_this_insert = false
92
+
93
+ end
94
+
95
+ def create_table sql_columns_string
96
+ sql_columns_string = "#{sql_columns_string}"
97
+ # EXAMPLE sql_columns_string = "id INTEGER PRIMARY KEY, name_first VARCHAR(255), name_last VARCHAR(255)) ORDER BY id SEGMENTED BY HASH(id) ALL NODES"
98
+ query = "CREATE TABLE #{@name_of_table} (#{sql_columns_string}) ORDER BY id SEGMENTED BY HASH(id) ALL NODES"
99
+
100
+ puts "#{Time.now} => ADS:#{query}" if GoodDataMarketo.logging
101
+
102
+ columns = sql_columns_string.split(', ')
103
+ columns.map! { |column|
104
+ s = column.split(' ')
105
+
106
+ case s[0]
107
+ when 'sys_capture_date' then s[1] = 'DATETIME'
108
+ when 'activity_date_time' then s[1] = 'DATETIME'
109
+ else s[1] = 'VARCHAR(255)'
110
+ end
111
+
112
+ { :column_name => s[0], :data_type => s[1] }
113
+ }
114
+
115
+ puts "#{Time.now} => ADS:CreateTable:#{query}" if GoodDataMarketo.logging
116
+
117
+ tries = 3
118
+ begin
119
+ @dwh.create_table(@name_of_table, columns)
120
+
121
+ rescue Exception => exp
122
+ puts exp if GoodDataMarketo.logging
123
+ end
124
+
125
+ end
126
+
127
+ def add_column column, config = {}
128
+ # EXAMPLE column = 'column_name'
129
+ type = config[:type] || 'VARCHAR(255)'
130
+ query = "ALTER TABLE #{@name_of_table} ADD COLUMN #{column} #{type}"
131
+ puts "#{Time.now} => ADS:Query: #{query}"
132
+
133
+ tries = 3
134
+ begin
135
+ @dwh.execute(query)
136
+ rescue Exception => exp
137
+ tries -= 1
138
+ if tries > 0
139
+ sleep 3
140
+
141
+ retry
142
+ else
143
+ puts exp if GoodDataMarketo.logging
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ def remove_column column
150
+ # EXAMPLE column = 'column_name'
151
+ self.log query = "ALTER TABLE #{@name_of_table} DROP COLUMN #{column}"
152
+ tries = 3
153
+ begin
154
+ @dwh.execute(query)
155
+ rescue Exception => exp
156
+ tries -= 1
157
+ if tries > 0
158
+ sleep 3
159
+ retry
160
+ else
161
+ puts exp if GoodDataMarketo.logging
162
+ end
163
+ end
164
+ end
165
+
166
+ alias :drop_column :remove_column
167
+
168
+ def columns
169
+ @dwh.get_columns(@name_of_table).map { |column| column[:column_name] }
170
+ end
171
+
172
+ def select command
173
+
174
+ rows = []
175
+ @dwh.execute_select(command) do |row|
176
+ puts row
177
+ rows << row
178
+ end
179
+ self.log rows
180
+
181
+ end
182
+
183
+ alias :query :select
184
+
185
+ def columns_array_to_string columns_string_array
186
+
187
+ c = []
188
+ columns_string_array.each {|a| c << a }
189
+ id = "#{c.shift.downcase}"
190
+ self.log columns = c.map { |column|
191
+ "#{column.gsub(' ','').downcase}"
192
+ }
193
+
194
+ res = columns.unshift(id)
195
+ res.join(', ')
196
+
197
+ end
198
+
199
+ def columns_array_to_sql columns_array
200
+
201
+ c = []
202
+ columns_array.each {|a| c << a }
203
+ id = "#{c.shift.downcase} VARCHAR(255)"
204
+ columns = c.map { |column|
205
+ "#{column.gsub(' ','').downcase} VARCHAR(255)"
206
+ }
207
+
208
+ res = columns.unshift(id)
209
+ res.join(', ')
210
+
211
+ end
212
+
213
+ def export_to_csv file_path
214
+ tries = 3
215
+ begin
216
+ @dwh.export_to_csv @name_of_table, file_path
217
+ rescue Exception => exp
218
+ tries -= 1
219
+ if tries > 0
220
+ sleep 3
221
+ retry
222
+ else
223
+ puts exp if GoodDataMarketo.logging
224
+ end
225
+ end
226
+
227
+ end
228
+
229
+ def check_for_sql_parse_errors text
230
+
231
+ list = ReservedSqlKeywords.new
232
+ keywords = list.values
233
+
234
+ if keywords.include? text.upcase
235
+ puts "#{Time.now} => WARNING: Updated column key \"#{text}\" to \"#{text}\" as it is a SQL reserved keyword." if GoodDataMarketo.logging
236
+ text="#{text}_m"
237
+ else
238
+ text
239
+ end
240
+
241
+ end
242
+
243
+ def merge_columns config = {}
244
+
245
+ columns = config[:merge_with] || config[:columns]
246
+
247
+ @checked_columns_this_insert = true
248
+ # Set up Leads Table
249
+
250
+ # Check the table columns
251
+ current_columns = []
252
+
253
+ if @cached_columns
254
+ current_columns = @cached_columns
255
+ else
256
+
257
+ @dwh.get_columns(@name_of_table).each do |object|
258
+ current_columns << object[:column_name]
259
+ end
260
+
261
+ @cached_columns = current_columns
262
+
263
+ end
264
+
265
+ proposed_columns = columns.map do |column|
266
+ column.gsub(' ','').downcase
267
+ end
268
+
269
+ identical_columns = proposed_columns & current_columns == proposed_columns
270
+
271
+ if identical_columns
272
+
273
+ self.log proposed_columns
274
+
275
+ else # Find the columns that are not in the current columns and add them.
276
+
277
+ update_column_queue = Array.new
278
+
279
+ proposed_columns.pmap do |check_column|
280
+
281
+ if current_columns.find_index(check_column)
282
+ next # Column
283
+ else
284
+ puts "#{Time.now} => Adding new column:#{@name_of_table}:#{check_column}" if GoodDataMarketo.logging
285
+
286
+ check_column = self.check_for_sql_parse_errors(check_column)
287
+
288
+ @cached_columns << check_column # Add the column to the cache
289
+
290
+ @cached_columns.uniq!
291
+
292
+ type = 'VARCHAR(255)'
293
+
294
+ self.add_column(check_column, :type => type)
295
+
296
+ end
297
+
298
+ end
299
+
300
+ puts "#{Time.now} => Table #{@name_of_table} Merge Complete."
301
+
302
+ # If config BOOL = true also removed columns not found in the proposed columns in the warehouse
303
+ if config[:two_way] || config[:sync]
304
+ current_columns.each do |check_current_column|
305
+ if proposed_columns.find_index(check_current_column)
306
+ next # Column
307
+ else
308
+ self.log "#{Time.now} => TABLE:#{@name_of_table} + new column:#{check_current_column}"
309
+ self.remove_column(check_current_column)
310
+ end
311
+ end
312
+
313
+ end
314
+
315
+ end
316
+
317
+ end
318
+
319
+ def name=
320
+ @name_of_table
321
+ end
322
+
323
+ end
@@ -0,0 +1,118 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ class WebDAV
5
+
6
+ attr_accessor :project
7
+ attr_accessor :user
8
+ attr_accessor :password
9
+
10
+ def initialize config = {}
11
+
12
+ self.user = config[:user]
13
+ self.password = config[:pass] || config[:password]
14
+ self.project = config[:project] || config[:pid]
15
+
16
+ raise 'ERROR! :user, :password, & :project must be passed in the configuration.' unless self.user && self.project && self.password
17
+
18
+ @uri = URI.parse("https://secure-di.gooddata.com/project-uploads/")
19
+
20
+ end
21
+
22
+ def test
23
+ begin
24
+ test = self.exists? 'file'
25
+ puts "#{Time.now} => SETUP: Connect to GoodData WebDAV...success!" if GoodDataMarketo.logging
26
+ true
27
+ rescue
28
+ false
29
+ end
30
+ end
31
+
32
+ def upload file
33
+ http = Net::HTTP.new(@uri.host, @uri.port)
34
+ http.use_ssl = @uri.scheme == 'https'
35
+
36
+ request = Net::HTTP::Put.new("#{@uri.request_uri}/#{file}")
37
+ request.basic_auth self.user, self.password
38
+ request.body_stream = File.open(file)
39
+ request["Content-Type"] = "multipart/form-data"
40
+ request.add_field('Content-Length', File.size(file))
41
+
42
+ response = http.request(request)
43
+ if response.is_a?(Net::HTTPSuccess)
44
+ response
45
+ else
46
+ false
47
+ end
48
+
49
+ end
50
+
51
+ def download file
52
+ Net::HTTP.start(@uri.host, @uri.port,
53
+ :use_ssl => @uri.scheme == 'https') do |http|
54
+ request = Net::HTTP::Get.new @uri+file
55
+ request.basic_auth self.user, self.password
56
+
57
+ response = http.request request
58
+ if response.is_a?(Net::HTTPSuccess)
59
+ response.body
60
+ else
61
+ false
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ def get_marketo_etl_controller
68
+ self.download('marketo_connector.json')
69
+ end
70
+
71
+ def set_marketo_etl_controller
72
+ self.upload('marketo_connector.json')
73
+ end
74
+
75
+ def exists? file
76
+
77
+ Net::HTTP.start(@uri.host, @uri.port,
78
+ :use_ssl => @uri.scheme == 'https') do |http|
79
+
80
+ request = Net::HTTP::Get.new "#{@uri.to_s}#{file}/"
81
+ request.basic_auth self.user, self.password
82
+
83
+ response = http.request request
84
+ if response.is_a?(Net::HTTPSuccess)
85
+ if response.code == "200"
86
+ true
87
+ else
88
+ false
89
+ end
90
+ else
91
+ false
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+ alias :include? :exists?
98
+
99
+ def delete file
100
+ Net::HTTP.start(@uri.host, @uri.port,
101
+ :use_ssl => @uri.scheme == 'https') do |http|
102
+
103
+ request = Net::HTTP::Delete.new @uri+file
104
+ request.basic_auth self.user, self.password
105
+
106
+ response = http.request request
107
+ if response.is_a?(Net::HTTPSuccess)
108
+ response.body
109
+ else
110
+ false
111
+ end
112
+ end
113
+
114
+ end
115
+
116
+
117
+ end
118
+