gooddata_marketo 0.0.1-java

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.
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
+