cxf 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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +12 -0
  3. data/README.md +395 -0
  4. data/lib/client.rb +447 -0
  5. data/lib/contact/config/config.rb +4 -0
  6. data/lib/contact/content/content.rb +4 -0
  7. data/lib/contact/ecommerce/ecommerce.rb +4 -0
  8. data/lib/contact.rb +284 -0
  9. data/lib/cxf/controllers/admin_base_controller.rb +17 -0
  10. data/lib/cxf/controllers/base_api_controller.rb +28 -0
  11. data/lib/cxf/controllers/base_controller.rb +54 -0
  12. data/lib/cxf/controllers/concerns/cxf_clients.rb +104 -0
  13. data/lib/cxf/controllers/concerns/read_config_file.rb +30 -0
  14. data/lib/cxf/controllers/contact_api_controller.rb +17 -0
  15. data/lib/cxf/controllers/public_api_controller.rb +14 -0
  16. data/lib/cxf/controllers/user_api_controller.rb +16 -0
  17. data/lib/cxf/helpers/contact_auth_helper.rb +86 -0
  18. data/lib/cxf/helpers/cxf_helper.rb +52 -0
  19. data/lib/cxf/helpers/proxy_controllers_methods.rb +144 -0
  20. data/lib/cxf/helpers/threads_helper.rb +109 -0
  21. data/lib/cxf/helpers/user_auth_helper.rb +74 -0
  22. data/lib/cxf.rb +15 -0
  23. data/lib/errors.rb +109 -0
  24. data/lib/generators/cxf_assets_controller.rb +7 -0
  25. data/lib/generators/cxf_config.yml.erb +27 -0
  26. data/lib/generators/cxf_contact_controller.rb +7 -0
  27. data/lib/generators/cxf_files_generator.rb +28 -0
  28. data/lib/generators/cxf_public_controller.rb +7 -0
  29. data/lib/generators/cxf_user_controller.rb +7 -0
  30. data/lib/pub/config/config.rb +6 -0
  31. data/lib/pub/content/assets.rb +16 -0
  32. data/lib/pub/content/content.rb +9 -0
  33. data/lib/pub/ecommerce/ecommerce.rb +6 -0
  34. data/lib/pub.rb +163 -0
  35. data/lib/user/config/attribute_groups.rb +79 -0
  36. data/lib/user/config/attributes.rb +88 -0
  37. data/lib/user/config/calendars.rb +91 -0
  38. data/lib/user/config/config.rb +23 -0
  39. data/lib/user/config/relationships.rb +141 -0
  40. data/lib/user/config/seeds.rb +55 -0
  41. data/lib/user/config/system_settings.rb +54 -0
  42. data/lib/user/config/tags.rb +61 -0
  43. data/lib/user/config/taxonomies.rb +120 -0
  44. data/lib/user/config/users.rb +77 -0
  45. data/lib/user/config/views.rb +68 -0
  46. data/lib/user/contacts/contacts.rb +22 -0
  47. data/lib/user/content/assets.rb +294 -0
  48. data/lib/user/content/block_templates.rb +72 -0
  49. data/lib/user/content/blocks.rb +109 -0
  50. data/lib/user/content/content.rb +174 -0
  51. data/lib/user/content/instances.rb +121 -0
  52. data/lib/user/content/print_versions.rb +129 -0
  53. data/lib/user/content/stories.rb +110 -0
  54. data/lib/user/content/story_templates.rb +97 -0
  55. data/lib/user/content/templates.rb +72 -0
  56. data/lib/user/crm/companies.rb +111 -0
  57. data/lib/user/crm/contacts.rb +294 -0
  58. data/lib/user/crm/crm.rb +9 -0
  59. data/lib/user/ecommerce/ecommerce.rb +29 -0
  60. data/lib/user/ecommerce/item_prices.rb +89 -0
  61. data/lib/user/ecommerce/locations.rb +171 -0
  62. data/lib/user/ecommerce/price_lists.rb +75 -0
  63. data/lib/user/ecommerce/product_templates.rb +106 -0
  64. data/lib/user/ecommerce/product_variations.rb +133 -0
  65. data/lib/user/ecommerce/product_versions.rb +107 -0
  66. data/lib/user/ecommerce/products.rb +156 -0
  67. data/lib/user/ecommerce/skus.rb +90 -0
  68. data/lib/user/ecommerce/taxes.rb +84 -0
  69. data/lib/user/ecommerce/variant_options.rb +71 -0
  70. data/lib/user/ecommerce/variant_values.rb +74 -0
  71. data/lib/user/ecommerce/vouchers.rb +90 -0
  72. data/lib/user/helpers/helpers.rb +116 -0
  73. data/lib/user/helpers/object_activities.rb +85 -0
  74. data/lib/user/helpers/object_folders.rb +84 -0
  75. data/lib/user/helpers/user_folders.rb +85 -0
  76. data/lib/user/marketing/marketing.rb +123 -0
  77. data/lib/user/profile/profile.rb +104 -0
  78. data/lib/user.rb +98 -0
  79. metadata +227 -0
data/lib/client.rb ADDED
@@ -0,0 +1,447 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cxf/helpers/cxf_helper'
4
+ require 'httparty'
5
+ require 'json'
6
+ require 'addressable'
7
+ require 'redis'
8
+ require_relative './cxf/controllers/concerns/read_config_file'
9
+
10
+ module Cxf
11
+ class Client
12
+ extend ActiveSupport::Concern
13
+ include CxfHelper
14
+
15
+ attr_reader :host, :mode, :api_key, :scope, :base_url
16
+ attr_accessor :session_token, :refresh_token, :contact_token_id, :session_token_expires_at, :refresh_token_expires_at
17
+
18
+ def initialize(
19
+ host,
20
+ api_key,
21
+ scope = nil,
22
+ session_token = nil,
23
+ refresh_token = nil,
24
+ contact_token_id = nil,
25
+ visit_id = nil,
26
+ debug = false,
27
+ timeouts = {}
28
+ )
29
+
30
+ @host = host
31
+ @api_key = api_key
32
+ @session_token = session_token
33
+ @session_token_expires_at = nil
34
+ @refresh_token = refresh_token
35
+ @refresh_token_expires_at = nil
36
+ @contact_token_id = contact_token_id
37
+ @visit_id = visit_id
38
+ @debug = debug
39
+
40
+ config = read_config_file('sdk') || {}
41
+
42
+ @default_http_timeout = timeouts.fetch(:default, config.fetch('default_http_timeout', 30))
43
+ @get_http_timeout = timeouts.fetch(:get, config.fetch('get_http_timeout', @default_http_timeout))
44
+ @post_http_timeout = timeouts.fetch(:post, config.fetch('post_http_timeout', @default_http_timeout))
45
+ @put_http_timeout = timeouts.fetch(:put, config.fetch('put_http_timeout', @default_http_timeout))
46
+ @delete_http_timeout = timeouts.fetch(:delete, config.fetch('delete_http_timeout', @default_http_timeout))
47
+
48
+ self.set_scope(scope)
49
+ end
50
+
51
+ def raw(action, url, options = nil, data = nil, base_url = nil, compatibility_options = {}, only_tracking = false, disable_data_transform = false)
52
+ compatibility_options = {} if compatibility_options.nil?
53
+
54
+ data = data_transform(data) unless disable_data_transform or action == 'get'
55
+
56
+ base_url = @base_url unless base_url
57
+ uri = ''
58
+
59
+ # get the first method called in this instance, example: get_deal(1)
60
+ method_called = caller[0][/`.*'/][1..-2]
61
+
62
+ # this can't be "!url.last.to_i" because we have methods like .me
63
+ if is_singular?(method_called) && %w[// nil].include?(url)
64
+ error_class = Errors::DynamicError.new(
65
+ self,
66
+ 'Unprocessed entity',
67
+ "Id must be a valid integer number, given URL: #{url}",
68
+ 'undefined_id',
69
+ nil
70
+ )
71
+
72
+ raise error_class if @debug
73
+
74
+ raise error_class.error
75
+ end
76
+
77
+ if options&.class == Hash
78
+ need_encoding = %w[jfilters afilters rfilters]
79
+ found_options_with_encoding = options.keys.select { |key| need_encoding.include?(key.to_s.downcase) and options[key]&.class == Hash }
80
+
81
+ found_options_with_encoding.each do |key|
82
+ options[key] = CGI::escape(Base64.encode64(options[key].to_json))
83
+ end
84
+
85
+ uri = Addressable::URI.new
86
+ uri.query_values = options
87
+ end
88
+
89
+ full_url = "#{@host}#{base_url}#{url}#{uri}"
90
+ response = nil
91
+
92
+ template = ERB.new File.new("#{Rails.root}/cxf_config.yml.erb").read
93
+ config = YAML.safe_load template.result(binding)
94
+ result_from_cache = false
95
+
96
+ if action === 'get'
97
+ url_need_cache = false
98
+
99
+ if config['redis_cache']['use_cache']
100
+ config['redis_cache']['groups'].each do |group|
101
+ group['urls'].each do |url|
102
+ if full_url.match url
103
+ time = group['time']
104
+ url_need_cache = true
105
+ @redis_server = Redis.new(
106
+ host: config['redis_cache']['redis_host'],
107
+ port: config.dig('redis_cache', 'redis_port') || 6379,
108
+ db: config.dig('redis_cache', 'redis_db') || 1
109
+ )
110
+ response = @redis_server.get(full_url)
111
+
112
+ if response
113
+ result_from_cache = true
114
+
115
+ if only_tracking
116
+ # headers = { 'Only-Tracking' => 'true' }
117
+ # when is already in redis notify to California to register the object usage
118
+ # cali_response = self.send("#{@scope}_#{action}", full_url, headers, compatibility_options)
119
+ end
120
+ else
121
+ response = self.send("#{@scope}_#{action}", full_url, nil, compatibility_options)
122
+ @redis_server.setex(full_url, time, response)
123
+ end
124
+ break
125
+ end
126
+ end
127
+
128
+ break if url_need_cache
129
+ end
130
+ end
131
+
132
+ unless url_need_cache
133
+ response = self.send("#{@scope}_#{action}", full_url, nil, compatibility_options)
134
+ replace_tokens(response)
135
+ end
136
+
137
+ elsif action === 'create' or action === 'post'
138
+ action = 'post'
139
+ response = self.send("#{@scope}_#{action}", full_url, data, compatibility_options)
140
+ replace_tokens(response)
141
+ elsif action === 'put' or action === 'patch' or action === 'update'
142
+ action = 'put'
143
+ response = self.send("#{@scope}_#{action}", full_url, data, compatibility_options)
144
+ replace_tokens(response)
145
+ elsif action === 'delete' or action === 'destroy'
146
+ action = 'delete'
147
+ response = self.send("#{@scope}_#{action}", full_url, data, compatibility_options)
148
+ replace_tokens(response)
149
+ end
150
+
151
+ verify_response_status(response, config['sdk']['ignore_http_errors'])
152
+
153
+ begin
154
+ if @debug
155
+ response_from = if result_from_cache
156
+ 'REDIS'
157
+ else
158
+ 'CALI'
159
+ end
160
+
161
+ puts "Method: #{action} \nURL: #{url} \nOptions: #{options&.to_json} \nOnly tracking: #{only_tracking} \nResponse from: #{response_from}"
162
+ puts "Data: #{data.to_json}" if data
163
+ end
164
+
165
+ if result_from_cache
166
+ return JSON.parse(response)
167
+ else
168
+ return JSON.parse(response&.body)
169
+ end
170
+ rescue
171
+ return response
172
+ end
173
+ end
174
+
175
+ def method_missing(name, *args, &block)
176
+ name.to_s.include?('__') ? separator = '__' : separator = '_'
177
+ # split the name to identify their elements
178
+ name_splitted = name.to_s.split(separator)
179
+ # count the elements
180
+ name_len = name_splitted.size
181
+ # the action always be the first element
182
+ action = name_splitted.first
183
+ valid_actions = %w[
184
+ get
185
+ create
186
+ post
187
+ update
188
+ put
189
+ delete
190
+ destroy
191
+ verify_response_status
192
+ ]
193
+
194
+ raise 'NoActionError' unless valid_actions.include?(action)
195
+
196
+ # the object always be the last element
197
+ object = separator == '__' ? name_splitted.last.gsub('_', '-') : name_splitted.last
198
+ # get intermediate url elements
199
+ route_array = []
200
+ (name_len - 1).times do |n|
201
+ next if n === 0 or n === name_len - 1
202
+
203
+ n = name_splitted[n]
204
+ self.replacements.each do |object|
205
+ n = n.gsub(object[:old_value], object[:new_value])
206
+ end
207
+ route_array.push n
208
+ end
209
+ route = route_array.join('/')
210
+
211
+ slug = nil
212
+ response = nil
213
+ uri = Addressable::URI.new
214
+
215
+ if action == 'get'
216
+ if args.first.class == Hash
217
+ uri.query_values = args.first
218
+ elsif args.first.class == String or Integer
219
+ slug = args.first
220
+ uri.query_values = args[1]
221
+ end
222
+
223
+ url = self.get_url(route, object, uri, slug)
224
+ response = self.send("#{@scope}_#{action}", url, nil, compatibility_options)
225
+ elsif action == 'post' or action == 'create'
226
+ if args[1].class == Hash
227
+ uri.query_values = args[1]
228
+ end
229
+
230
+ url = self.get_url(route, object, uri, slug)
231
+ action = 'post'
232
+ data = args[0]
233
+ response = self.send("#{@scope}_#{action}", url, { data: data }, compatibility_options)
234
+ elsif action == 'put' or action == 'update'
235
+ if args.first.class == String or Integer
236
+ slug = args.first
237
+ uri.query_values = args[2]
238
+ end
239
+
240
+ url = self.get_url(route, object, uri, slug)
241
+ action = 'put'
242
+ data = args[1]
243
+ response = self.send("#{@scope}_#{action}", "#{url}", { data: data }, compatibility_options)
244
+ end
245
+
246
+ verify_response_status(response, config['sdk']['ignore_http_errors'])
247
+
248
+ response ? JSON.parse(response.body) : nil
249
+ end
250
+
251
+ def get_url(route, object, uri, slug = nil)
252
+ if slug
253
+ "#{@host}#{@base_url}/#{route}/#{object}/#{slug}#{uri}"
254
+ else
255
+ "#{@host}#{@base_url}/#{route}/#{object}#{uri}"
256
+ end
257
+ end
258
+
259
+ def replacements
260
+ [
261
+ { old_value: '_', new_value: '-' },
262
+ { old_value: 'people', new_value: 'crm' },
263
+ { old_value: 'store', new_value: 'ecommerce' }
264
+ ]
265
+ end
266
+
267
+ def set_scope(scope)
268
+ @scope = scope
269
+ if scope === 'public' or scope === 'contact'
270
+ @base_url = '/api/v1'
271
+ elsif scope === 'user'
272
+ @base_url = '/api/user/v1'
273
+ else
274
+ @scope = 'public'
275
+ @base_url = '/api/v1'
276
+ end
277
+ end
278
+
279
+ ##### HTTP CLIENTS ######
280
+ # Simple HTTP GET
281
+ def http_get(url, headers = nil)
282
+ HTTParty.get(url, headers: headers, timeout: @get_http_timeout)
283
+ end
284
+
285
+ # Simple HTTP POST
286
+ def http_post(url, headers = nil, data = nil)
287
+ HTTParty.post(url, headers: headers, body: data, timeout: @post_http_timeout)
288
+ end
289
+
290
+ # Simple HTTP PUT
291
+ def http_put(url, headers = nil, data = nil)
292
+ HTTParty.put(url, headers: headers, body: data, timeout: @put_http_timeout)
293
+ end
294
+
295
+ # Simple HTTP DELETE
296
+ def http_delete(url, headers = nil, data = nil)
297
+ HTTParty.delete(url, headers: headers, body: data, timeout: @delete_http_timeout)
298
+ end
299
+
300
+ # Start contact context
301
+ def contact_get(url, headers = nil, compatibility_options)
302
+ h = set_headers(compatibility_options, headers)
303
+
304
+ self.http_get(url, h)
305
+ end
306
+
307
+ def contact_post(url, data, compatibility_options)
308
+ headers = set_headers(compatibility_options)
309
+
310
+ self.http_post(url, headers, data)
311
+ end
312
+
313
+ def contact_put(url, data, compatibility_options)
314
+ headers = set_headers(compatibility_options)
315
+
316
+ self.http_put(url, headers, data)
317
+ end
318
+
319
+ # Start User context
320
+ def user_get(url, headers = nil, compatibility_options)
321
+ h = set_headers(compatibility_options, headers)
322
+
323
+ self.http_get(url, h)
324
+ end
325
+
326
+ def user_post(url, data, compatibility_options)
327
+ self.http_post(url, set_headers(compatibility_options), data)
328
+ end
329
+
330
+ def user_put(url, data, compatibility_options)
331
+ self.http_put(url, set_headers(compatibility_options), data)
332
+ end
333
+
334
+ def user_delete(url, data, compatibility_options)
335
+ self.http_delete(url, set_headers(compatibility_options), data)
336
+ end
337
+
338
+ # End User Context
339
+
340
+ def public_get(url, headers = nil, compatibility_options)
341
+ self.http_get(url, set_headers(compatibility_options, headers))
342
+ end
343
+
344
+ def public_post(url, headers = nil, data, compatibility_options)
345
+ self.http_post(url, set_headers(compatibility_options, headers), data)
346
+ end
347
+
348
+ def public_put(url, headers = nil, data, compatibility_options)
349
+ self.http_put(url, set_headers(compatibility_options, headers), data)
350
+ end
351
+
352
+ def set_headers(compatibility_options, headers = nil)
353
+ h = {
354
+ 'Accept' => 'application/json',
355
+ 'ApiKey' => @api_key,
356
+ 'Access-Token' => @session_token || '',
357
+ 'Refresh-Token' => @refresh_token || ''
358
+ }
359
+ h['Content-Type'] = 'application/json' unless compatibility_options['no_content_type']
360
+ h['ContactToken'] = @contact_token_id if @contact_token_id
361
+ h['Visit-Id'] = @visit_id if @visit_id
362
+ h['Authorization'] = "Bearer #{@session_token}" if @session_token
363
+
364
+ if headers
365
+ headers.each do |k, v|
366
+ h[k] = v
367
+ end
368
+ end
369
+
370
+ h
371
+ end
372
+
373
+ def verify_response_status(response, ignore_http_errors)
374
+ # Verify if the response is cached
375
+ unless response.kind_of? String
376
+ # Raise an error if response code is not 2xx
377
+ http_status = response&.response&.code&.to_i || 500
378
+ is_success = (http_status >= 200 and http_status < 300)
379
+
380
+ if !is_success and !ignore_http_errors
381
+ title = "Request failed with status #{http_status}"
382
+ detail = response&.response&.message || 'Unknown error'
383
+
384
+ puts "Error detected: #{http_status}" if @debug
385
+ error_class = Errors::DynamicError.new(self, title, detail, http_status, response&.parsed_response)
386
+
387
+ raise error_class if @debug
388
+
389
+ raise error_class.error
390
+ end
391
+ end
392
+ end
393
+
394
+ # Timeouts methods
395
+
396
+ def timeout
397
+ {
398
+ default: @default_http_timeout,
399
+ get: @get_http_timeout,
400
+ post: @post_http_timeout,
401
+ put: @put_http_timeout,
402
+ delete: @delete_http_timeout
403
+ }
404
+ end
405
+
406
+ def timeout=(t)
407
+ if t.kind_of? Hash
408
+ t = t.with_indifferent_access
409
+ @default_http_timeout = t[:default] if t[:default]
410
+ @get_http_timeout = t[:get] if t[:get]
411
+ @post_http_timeout = t[:post] if t[:post]
412
+ @put_http_timeout = t[:put] if t[:put]
413
+ @delete_http_timeout = t[:delete] if t[:delete]
414
+ elsif t.kind_of? Integer
415
+ @default_http_timeout = t
416
+ @get_http_timeout = t
417
+ @post_http_timeout = t
418
+ @put_http_timeout = t
419
+ @delete_http_timeout = t
420
+ end
421
+ end
422
+
423
+ def read_config_file(config_key = nil)
424
+ template = ERB.new File.new("#{Rails.root}/cxf_config.yml.erb").read
425
+ config = YAML.safe_load template.result(binding)
426
+ config_key ? config[config_key] : config
427
+ rescue StandardError
428
+ nil
429
+ end
430
+
431
+ def is_singular?(str)
432
+ str.pluralize != str && str.singularize == str
433
+ end
434
+
435
+ def replace_tokens(response)
436
+ return unless response&.headers
437
+
438
+ # Return if the response does not have headers Access-Token and Refresh-Token
439
+ return unless response.headers.key?('Access-Token') && response.headers.key?('Refresh-Token')
440
+
441
+ @session_token = response.headers['Access-Token']
442
+ @refresh_token = response.headers['Refresh-Token']
443
+ @session_token_expires_at = Time.parse(response.headers['Access-Token-Expires-At'])
444
+ @refresh_token_expires_at = Time.parse(response.headers['Refresh-Token-Expires-At'])
445
+ end
446
+ end
447
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ContactConfig
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ContactContent
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ContactEcommerce
4
+ end