zuora_connect 2.1.1 → 3.0.0.pre.e

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0342c5ac7396b4e8ba75aff8dbab5d579fa6d0ad04a421b7d1d809ab3abbd90a
4
- data.tar.gz: 70f7277a93fec8e481f63e56f85e466b5e0b4d1307e2413e4f8da9497e980be2
3
+ metadata.gz: 3f36eda986a37f2574d06c4e34785ba6da29d6dc1b4308744e8e73defd48c25a
4
+ data.tar.gz: 9b29a5f07f44fd2ba9df5440498fd1de7a9683654ca0ec7c742def938df8c166
5
5
  SHA512:
6
- metadata.gz: eb6497a343dde2b4a3edfe470c8e5a44eb37ff99b75ed434138c280e8ac25bf36806d58fbb477772182596917f1c37c0e237bd55e88f646e149743477fba2f15
7
- data.tar.gz: f0b1f8b6f647f204ce8c4bfed7a8e77b49f3aada0faf6a0c31fc47675f5bfca67feb464692006bcb490977a577d1d5a3feab53886815f4c6472023e9ade6823b
6
+ metadata.gz: ce99e27b914104c581943f5abed30d298841e402d6a76c53884c2041a4d1bf9780f063357f865ead9e8b144ade8dc8ac7d5fbdd64bfe54bb9a833df32ad30fa3
7
+ data.tar.gz: 5b108c5a4048412c39f0f5fb99c76532c0671012fb47c92397239c999fe7c0ea48af10132e41acb80f9957a6415282faea9c840c84f9c104bb268cce9de8812d
@@ -1,23 +1,20 @@
1
1
  module ZuoraConnect
2
2
  class StaticController < ApplicationController
3
- before_action :authenticate_connect_app_request, :except => [:metrics, :health, :initialize_app]
4
- before_action :clear_connect_app_session, :only => [:metrics, :health, :initialize_app]
5
- after_action :persist_connect_app_session, :except => [:metrics, :health, :initialize_app]
6
-
7
- skip_before_action :verify_authenticity_token, :only => [:initialize_app]
8
-
9
- def metrics
10
- type = params[:type].present? ? params[:type] : "versions"
11
- render json: ZuoraConnect::AppInstance.get_metrics(type).to_json, status: 200
12
- end
3
+ before_action :authenticate_connect_app_request, :except => [:health, :initialize_app, :provision, :instance_user]
4
+ before_action :clear_connect_app_session, :only => [:health, :initialize_app, :provision, :instance_user]
5
+ after_action :persist_connect_app_session, :except => [:health, :initialize_app, :provision, :instance_user]
6
+
7
+ skip_before_action :verify_authenticity_token, :only => [:initialize_app, :provision]
8
+ http_basic_authenticate_with name: ENV['PROVISION_USER'], password: ENV['PROVISION_SECRET'], :only => [:provision, :instance_user]
9
+
13
10
 
14
11
  def health
15
12
  if params[:error].present?
16
- begin
13
+ begin
17
14
  raise ZuoraConnect::Exceptions::Error.new('This is an error')
18
15
  rescue => ex
19
16
  case params[:error]
20
- when 'Log'
17
+ when 'Log'
21
18
  Rails.logger.error("Error in Health", ex)
22
19
  when 'Exception'
23
20
  raise
@@ -34,11 +31,13 @@ module ZuoraConnect
34
31
  def initialize_app
35
32
  begin
36
33
  authenticate_connect_app_request
37
- @appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
38
- render json: {
39
- message: "Success",
40
- status: 200
41
- }, status: 200
34
+ unless performed?
35
+ @appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
36
+ render json: {
37
+ message: 'Success',
38
+ status: 200
39
+ }, status: 200
40
+ end
42
41
  rescue => ex
43
42
  Rails.logger.error("Failed to Initialize application", ex)
44
43
  if performed?
@@ -52,6 +51,74 @@ module ZuoraConnect
52
51
  end
53
52
  end
54
53
 
54
+ def provision
55
+ create_new_instance
56
+ unless performed?
57
+ render json: {
58
+ status: 200,
59
+ message: 'Success',
60
+ app_instance_id: @appinstance.id
61
+ }, status: 200
62
+ end
63
+ rescue StandardError => e
64
+ message = 'Failed to provision new instance'
65
+ if performed?
66
+ Rails.logger.error("#{message}: #{performed?}", e)
67
+ else
68
+ Rails.logger.error(message, e)
69
+ render json: {
70
+ status: 500,
71
+ message: message
72
+ }, status: 500
73
+ end
74
+ end
75
+
76
+ def instance_user
77
+ ZuoraConnect::AppInstance.read_master_db do
78
+ ZuoraConnect.logger.with_fields = {} if ZuoraConnect.logger.is_a?(Ougai::Logger)
79
+ Rails.logger.with_fields = {} if Rails.logger.is_a?(Ougai::Logger)
80
+
81
+ if defined?(ElasticAPM) && ElasticAPM.running? && ElasticAPM.respond_to?(:set_label)
82
+ ElasticAPM.set_label(:trace_id, request.uuid)
83
+ end
84
+
85
+ unless params[:id].present?
86
+ render json: {
87
+ status: 400,
88
+ message: 'No app instance id provided'
89
+ }, status: :bad_request
90
+ return
91
+ end
92
+
93
+ @appinstance = ZuoraConnect::AppInstance.find(params[:id]).new_session
94
+ end
95
+
96
+ zuora_client = @appinstance.send(ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION).client
97
+ client_describe, = zuora_client.rest_call(
98
+ url: zuora_client.rest_endpoint('genesis/user/info').gsub('v1/', ''),
99
+ session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic
100
+ )
101
+
102
+ render json: {
103
+ status: 200,
104
+ message: 'Success',
105
+ user_id: client_describe['coreUserId'],
106
+ username: client_describe['username'],
107
+ email: client_describe['workEmail']
108
+ }, status: 200
109
+ rescue ActiveRecord::RecordNotFound
110
+ render json: {
111
+ status: 400,
112
+ message: 'No app instance found'
113
+ }, status: :bad_request
114
+ rescue StandardError => e
115
+ Rails.logger.error('Error occurred getting user details', e)
116
+ render json: {
117
+ status: 500,
118
+ message: 'Failed to get user details'
119
+ }, status: 500
120
+ end
121
+
55
122
  private
56
123
 
57
124
  def clear_connect_app_session
@@ -11,8 +11,7 @@ module ZuoraConnect
11
11
  before_destroy :prune_data
12
12
 
13
13
  self.table_name = "zuora_connect_app_instances"
14
- attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version, :drop_message, :new_session_message, :connect_user, :logitems
15
- @@telegraf_host = nil
14
+ attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version, :drop_message, :new_session_message, :connect_user, :logitems, :user_timezone
16
15
  REFRESH_TIMEOUT = 2.minute #Used to determine how long to wait on current refresh call before executing another
17
16
  INSTANCE_REFRESH_WINDOW = 1.hours #Used to set how how long till app starts attempting to refresh cached task connect data
18
17
  INSTANCE_REDIS_CACHE_PERIOD = 24.hours #Used to determine how long to cached task data will live for
@@ -21,6 +20,12 @@ module ZuoraConnect
21
20
  HOLDING_PATTERN_SLEEP = 5.seconds
22
21
  CONNECT_APPLICATION_ID = 0
23
22
  CONNECT_COMMUNICATION_SLEEP = Rails.env.test? ? 0.seconds : 5.seconds
23
+ CATALOG_LOOKUP_PAGE_SIZE = 10_000
24
+ CATALOG_LOOKUP_CACHE_TIME_KEY = 'CatalogCachedAt'
25
+ CATALOG_LOOKUP_TTL = 60.seconds
26
+ CATALOG_LOOKUP_CACHE_RESULT_KEY = 'CatalogCache'
27
+ TIMEZONE_LOG_RATE_LIMIT_KEY = 'TimezoneLoggedAt'
28
+ TIMEZONE_LOG_PERIOD = 4.hours
24
29
  IGNORED_LOCALS = ['fr', 'ja', 'es', 'zh', 'de']
25
30
  INTERNAL_HOSTS = []
26
31
  LOGIN_TENANT_DESTINATION = 'target_login'
@@ -29,7 +34,7 @@ module ZuoraConnect
29
34
  Aws::Errors::MissingCredentialsError,
30
35
  Aws::S3::Errors::AccessDenied,
31
36
  Aws::SES::Errors::AccessDenied,
32
- Aws::KMS::Errors::AccessDeniedException
37
+ Aws::KMS::Errors::AccessDeniedException
33
38
  ].freeze
34
39
  AWS_AUTH_ERRORS_MSG = "AWS Auth Errors".freeze
35
40
 
@@ -163,6 +168,7 @@ module ZuoraConnect
163
168
  end
164
169
 
165
170
  self.build_task(task_data: mock_task_data, session: session)
171
+ self.set_backup_creds
166
172
  self.last_refresh = Time.now.to_i
167
173
  else
168
174
  time_expire = (session["#{self.id}::last_refresh"] || Time.now).to_i - INSTANCE_REFRESH_WINDOW.ago.to_i
@@ -240,7 +246,9 @@ module ZuoraConnect
240
246
  rescue I18n::InvalidLocale => ex
241
247
  ZuoraConnect.logger.error(ex) if !IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
242
248
  end
243
- Time.zone = self.timezone
249
+
250
+ self.set_timezone
251
+
244
252
  if self.task_data.present?
245
253
  tenants = self.task_data.fetch('tenant_ids', [])
246
254
  organizations = self.task_data.fetch('organizations', [])
@@ -255,7 +263,7 @@ module ZuoraConnect
255
263
  end
256
264
 
257
265
  params = {
258
- name: self.task_data.dig('name'),
266
+ name: self.task_data.dig('name'),
259
267
  zuora_entity_ids: (self.task_data.dig(LOGIN_TENANT_DESTINATION,'entities') || []).map{|e| e['id']}.uniq,
260
268
  zuora_tenant_ids: tenants.map(&:to_s).uniq,
261
269
  organizations: organizations
@@ -264,7 +272,7 @@ module ZuoraConnect
264
272
  client = self.send(LOGIN_TENANT_DESTINATION).client
265
273
  if defined?(client.rest_domain)
266
274
  ZuoraConnect::RequestIdMiddleware.zuora_rest_domain = client.rest_domain
267
- params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
275
+ params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
268
276
  end
269
277
  end
270
278
  params = params.reject{|k,v| !self.attributes.keys.member?(k.to_s) || self[k] == v}
@@ -272,12 +280,77 @@ module ZuoraConnect
272
280
  end
273
281
  end
274
282
 
275
- def refresh(session: {})
283
+ def set_timezone(timezone: self.timezone, type: :default)
284
+ if timezone.blank?
285
+ timezone = self.timezone
286
+ end
287
+
288
+ if type == :default
289
+ Time.zone = timezone
290
+ elsif type == :user
291
+ begin
292
+ sql = <<-eos
293
+ SELECT zuora_users.zuora_identity_response FROM "#{self.id}".zuora_users ORDER BY zuora_users.updated_at DESC LIMIT 1;
294
+ eos
295
+ user = ActiveRecord::Base.connection.execute(sql).to_a.first
296
+
297
+ if user.present?
298
+ zuora_identity_response = JSON.parse(user.fetch('zuora_identity_response', '{}'))
299
+ self.user_timezone = zuora_identity_response.values.first&.dig('timeZone')
300
+ else
301
+ if (Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
302
+ Rails.logger.error('Cannot find any user to set the timezone', app_instance_id: self.id)
303
+ Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
304
+ end
305
+ end
306
+ rescue => ex
307
+ Rails.logger.error('There is an error while getting timezone users', ex)
308
+ end
309
+
310
+ if self.user_timezone.present?
311
+ # connect instance which has a custom timezone
312
+ if !self.auto_deployed? && (
313
+ ActiveSupport::TimeZone[self.task_data.dig('user_settings', 'timezone') || '']&.utc_offset !=
314
+ ActiveSupport::TimeZone[self.user_timezone]&.utc_offset
315
+ )
316
+ if self.environment == 'Production' &&
317
+ (Redis.current.hget(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id).to_i + TIMEZONE_LOG_PERIOD.to_i) <= Time.now.to_i
318
+ ZuoraConnect.logger.error(
319
+ "Instance and user timezones are different. User has '#{self.user_timezone}' and " \
320
+ "instance has '#{self.task_data.dig('user_settings', 'timezone')}'",
321
+ app_instance_id: self.id
322
+ )
323
+ Redis.current.hset(TIMEZONE_LOG_RATE_LIMIT_KEY, self.id, Time.now.to_i)
324
+ end
325
+ self.user_timezone = nil
326
+ Time.zone = timezone
327
+ else
328
+ begin
329
+ Time.zone = self.user_timezone
330
+ rescue ArgumentError
331
+ Rails.logger.error('Malformed user timezone', app_instance_id: self.id)
332
+ Time.zone = timezone
333
+ end
334
+ end
335
+ else
336
+ Time.zone = timezone
337
+ end
338
+ end
339
+ rescue => e
340
+ Rails.logger.error('Malformed timezone used', e, app_instance_id: self.id)
341
+ Time.zone = self.timezone
342
+ end
343
+
344
+ def auto_deployed?
345
+ self.id >= 25000000
346
+ end
347
+
348
+ def refresh(session: {})
276
349
  refresh_count ||= 0
277
350
  skip_connect ||= false
278
351
  begin
279
352
  #Check how app was deployed
280
- if self.id < 25000000 && !skip_connect
353
+ if !self.auto_deployed? && !skip_connect
281
354
  self.check_oauth_state
282
355
  response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
283
356
 
@@ -289,16 +362,8 @@ module ZuoraConnect
289
362
  end
290
363
 
291
364
  self.build_task(task_data: parsed_json, session: session)
292
- if self.kms_key.present? && self.kms_key.match(/^arn:aws:.*/)
293
- begin
294
- self.zuora_logins = self.strip_cache_data(object: parsed_json.dup, keys: ['applications', 'tokens', 'user_settings'])
295
- self.save(:validate => false)
296
- rescue Aws::KMS::Errors::ValidationException, *AWS_AUTH_ERRORS => ex
297
- Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
298
- rescue => ex
299
- Rails.logger.error(AWS_AUTH_ERRORS_MSG, ex)
300
- end
301
- end
365
+ self.set_backup_creds
366
+ self.save(validate: false) if self.changed?
302
367
  else
303
368
  raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
304
369
  end
@@ -338,9 +403,21 @@ module ZuoraConnect
338
403
  raise
339
404
  end
340
405
 
406
+ def aws_secrets
407
+ (Rails.application.secrets.aws || {}).transform_keys { |key| key.to_s }
408
+ end
409
+
341
410
  #### START KMS ENCRYPTION Methods ####
411
+ def set_backup_creds
412
+ if self.kms_key.present? && self.kms_key.match(/^arn:aws:.*/) && self.task_data.present?
413
+ self.zuora_logins = self.strip_cache_data(object: self.task_data.dup, keys: ['applications', 'tokens', 'user_settings'])
414
+ end
415
+ end
416
+
342
417
  def zuora_logins=(val)
343
418
  write_attribute(:zuora_logins, kms_encrypt(val.to_json))
419
+ rescue Aws::KMS::Errors::ValidationException, Aws::KMS::Errors::NotFoundException, *AWS_AUTH_ERRORS => ex
420
+ Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
344
421
  end
345
422
 
346
423
  def zuora_logins
@@ -350,7 +427,7 @@ module ZuoraConnect
350
427
 
351
428
  def kms_decrypt(value)
352
429
  kms_tries ||= 0
353
- kms_client = Aws::KMS::Client.new({region: Rails.application.secrets.aws['AWS_REGION'], credentials: self.aws_auth_client}.delete_if { |k, v| v.blank? })
430
+ kms_client = Aws::KMS::Client.new({region: aws_secrets['AWS_REGION'], credentials: self.aws_auth_client}.delete_if { |k, v| v.blank? })
354
431
  resp = kms_client.decrypt({ciphertext_blob: [value].pack("H*") })
355
432
  return resp.plaintext
356
433
  rescue *AWS_AUTH_ERRORS => ex
@@ -365,7 +442,7 @@ module ZuoraConnect
365
442
 
366
443
  def kms_encrypt(value)
367
444
  kms_tries ||= 0
368
- kms_client = Aws::KMS::Client.new({region: Rails.application.secrets.aws['AWS_REGION'], credentials: self.aws_auth_client}.delete_if {|k,v| v.blank? })
445
+ kms_client = Aws::KMS::Client.new({region: aws_secrets['AWS_REGION'], credentials: self.aws_auth_client}.delete_if {|k,v| v.blank? })
369
446
 
370
447
  resp = kms_client.encrypt({key_id: kms_key, plaintext: value})
371
448
  return resp.ciphertext_blob.unpack('H*').first
@@ -380,12 +457,12 @@ module ZuoraConnect
380
457
  end
381
458
 
382
459
  def kms_key
383
- return ENV['AWS_KMS_ARN'] || Rails.application.secrets.dig(:aws,'AWS_KMS_ARN')
460
+ return ENV['AWS_KMS_ARN'] || aws_secrets['AWS_KMS_ARN']
384
461
  end
385
462
 
386
463
  def aws_auth_client
387
464
  if Rails.env.to_s == 'development'
388
- return Aws::Credentials.new(Rails.application.secrets.aws['AWS_ACCESS_KEY_ID'], Rails.application.secrets.aws['AWS_SECRET_ACCESS_KEY'])
465
+ return Aws::Credentials.new(aws_secrets['AWS_ACCESS_KEY_ID'], aws_secrets['AWS_SECRET_ACCESS_KEY'])
389
466
  else
390
467
  return nil
391
468
  end
@@ -400,82 +477,6 @@ module ZuoraConnect
400
477
  end
401
478
  Thread.current[:appinstance] = self
402
479
  end
403
-
404
- def self.write_to_telegraf(*args)
405
- if ZuoraConnect.configuration.enable_metrics
406
- @@telegraf_host = ZuoraConnect::Telegraf.new() if @@telegraf_host == nil
407
- unicorn_stats = self.unicorn_listener_stats() if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
408
- @@telegraf_host.write(direction: 'Raindrops', tags: {}, values: unicorn_stats) unless unicorn_stats.blank?
409
- return @@telegraf_host.write(*args)
410
- end
411
- end
412
-
413
- def self.unicorn_listener_stats ()
414
- stats_hash = {}
415
- stats_hash["total_active"] = 0
416
- stats_hash["total_queued"] = 0
417
-
418
- begin
419
- tmp = Unicorn.listener_names
420
- unix = tmp.grep(%r{\A/})
421
- tcp = tmp.grep(/\A.+:\d+\z/)
422
- tcp = nil if tcp.empty?
423
- unix = nil if unix.empty?
424
-
425
-
426
- Raindrops::Linux.tcp_listener_stats(tcp).each do |addr,stats|
427
- stats_hash["active_#{addr}"] = stats.active
428
- stats_hash["queued_#{addr}"] = stats.queued
429
- stats_hash["total_active"] = stats.active + stats_hash["total_active"]
430
- stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
431
- end if tcp
432
-
433
- Raindrops::Linux.unix_listener_stats(unix).each do |addr,stats|
434
- stats_hash["active_#{addr}"] = stats.active
435
- stats_hash["queued_#{addr}"] = stats.queued
436
- stats_hash["total_active"] = stats.active + stats_hash["total_active"]
437
- stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
438
- end if unix
439
- rescue IOError => ex
440
- rescue => ex
441
- ZuoraConnect.logger.error(ex)
442
- end
443
- return stats_hash
444
- end
445
-
446
- def self.get_metrics(type)
447
- @data = {}
448
-
449
- if type == "versions"
450
- @data = {
451
- app_name: ZuoraConnect::Telegraf.app_name,
452
- url: "dummy",
453
- Version_Gem: ZuoraConnect::VERSION,
454
- Version_Zuora: ZuoraAPI::VERSION ,
455
- Version_Ruby: RUBY_VERSION,
456
- Version_Rails: Rails.version,
457
- hold: 1
458
- }
459
- elsif type == "stats"
460
- begin
461
- Resque.redis.ping
462
- @resque = Resque.info
463
- @data = {
464
- app_name: ZuoraConnect::Telegraf.app_name,
465
- url: "dummy",
466
- Resque:{
467
- Jobs_Finished: @resque[:processed] ,
468
- Jobs_Failed: @resque[:failed],
469
- Jobs_Pending: @resque[:pending],
470
- Workers_Active: @resque[:working],
471
- Workers_Total: @resque[:workers]
472
- }
473
- }
474
- rescue
475
- end
476
- end
477
- return @data
478
- end
479
480
  #### END Task Methods ####
480
481
 
481
482
  #### START Task Methods ####
@@ -518,7 +519,7 @@ module ZuoraConnect
518
519
  end
519
520
  rescue ZuoraConnect::Exceptions::MissMatch => ex
520
521
  raise
521
- rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
522
+ rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
522
523
  raise
523
524
  rescue => ex
524
525
  ZuoraConnect.logger.error("Build Task Error", ex)
@@ -574,12 +575,12 @@ module ZuoraConnect
574
575
  self.refresh if !defined?(self.target_login)
575
576
 
576
577
  response = HTTParty.get("#{ZuoraConnect.configuration.url}/api/#{self.api_version}/tenants/search?hostname=#{self.target_login.client.hostname}&node_id=#{self.zuora_entity_ids.first}")
577
-
578
+
578
579
  if response.success?
579
580
  parsed_json = JSON.parse(response.body)
580
-
581
+
581
582
  #Set Org
582
- if self.id >= 25000000 && parsed_json['organization'].present?
583
+ if self.auto_deployed? && parsed_json['organization'].present?
583
584
  login_cache = self.zuora_logins
584
585
  login_cache.delete('organization')
585
586
  self.zuora_logins = login_cache.merge({'organizations' => [parsed_json['organization']]})
@@ -599,7 +600,7 @@ module ZuoraConnect
599
600
  end
600
601
  end
601
602
  self.save(:validate => false)
602
-
603
+
603
604
  return parsed_json
604
605
  end
605
606
  rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
@@ -653,7 +654,7 @@ module ZuoraConnect
653
654
  end
654
655
 
655
656
  def refresh_oauth
656
- refresh_oauth_count ||= 0
657
+ refresh_oauth_count ||= 0
657
658
  response = HTTParty.post("#{ZuoraConnect.configuration.url}/oauth/token", body: {
658
659
  :grant_type => "refresh_token",
659
660
  :redirect_uri => ZuoraConnect.configuration.oauth_client_redirect_uri,
@@ -955,13 +956,81 @@ module ZuoraConnect
955
956
  # object_id: The id or id's of the object/objects to be returned.
956
957
  # child_objects: Whether to include child objects of the object in question.
957
958
  # cache: Store individual "1" object lookup in redis for caching.
958
- def catalog_lookup(entity_id: nil, object: :product, object_id: nil, child_objects: false, cache: false)
959
+ def catalog_lookup(entity_id: nil, object: :product, object_id: nil, child_objects: false, cache: false, source: 'DB')
959
960
  entity_reference = entity_id.blank? ? 'Default' : entity_id
960
961
 
961
962
  if object_id.present? && ![Array, String].include?(object_id.class)
962
963
  raise "Object Id can only be a string or an array of strings"
963
964
  end
964
965
 
966
+ if source == 'API'
967
+ catalog_container = {}
968
+
969
+ if (Redis.current.hget(CATALOG_LOOKUP_CACHE_TIME_KEY, self.id).to_i + CATALOG_LOOKUP_TTL.to_i) > Time.now.to_i
970
+ begin
971
+ catalog_container = JSON.parse(Redis.current.hget(CATALOG_LOOKUP_CACHE_RESULT_KEY, self.id))
972
+ rescue JSON::ParserError => ex
973
+ Rails.logger.warn('Failed to parse catalog cache', ex)
974
+ end
975
+ else
976
+ zuora_login = self.login_lookup(type: 'Zuora').first
977
+ login = zuora_login.client(entity_reference)
978
+
979
+ response = {
980
+ 'nextPage' => login.rest_endpoint("catalog/products?pageSize=#{CATALOG_LOOKUP_PAGE_SIZE}")
981
+ }
982
+
983
+ while response['nextPage'].present?
984
+ url = login.rest_endpoint(response['nextPage'].split('/v1/').last)
985
+ output_json, response = login.rest_call(debug: false, url: url, timeout_retry: true)
986
+
987
+ case object
988
+ when :product
989
+ output_json.fetch('products', []).each do |product|
990
+ rate_plans = {}
991
+ product['productRatePlans'].each do |rate_plan|
992
+ charges = {}
993
+ rate_plan['productRatePlanCharges'].each do |charge|
994
+ charges[charge['id']] = charge.merge(
995
+ {
996
+ 'productId' => product['id'],
997
+ 'productName' => product['name'],
998
+ 'productRatePlanId' => rate_plan['id'],
999
+ 'productRatePlanName' => rate_plan['name'],
1000
+ }
1001
+ )
1002
+ end
1003
+
1004
+ rate_plan['productRatePlanCharges'] = charges
1005
+ rate_plans[rate_plan['id']] = rate_plan.merge(
1006
+ {
1007
+ 'productId' => product['id'],
1008
+ 'productName' => product['name']
1009
+ }
1010
+ )
1011
+ end
1012
+
1013
+ product['productRatePlans'] = rate_plans
1014
+ catalog_container[product['id']] = product
1015
+ end
1016
+ else
1017
+ raise "Available objects include [:product]"
1018
+ end
1019
+ end
1020
+
1021
+ Redis.current.hset(CATALOG_LOOKUP_CACHE_RESULT_KEY, self.id, catalog_container.to_json)
1022
+ Redis.current.hset(CATALOG_LOOKUP_CACHE_TIME_KEY, self.id, Time.now.to_i)
1023
+ end
1024
+
1025
+ if object_id.nil?
1026
+ catalog_container.transform_values! { |v| v.except('productRatePlans') }
1027
+ elsif object_id.is_a?(String)
1028
+ catalog_container = catalog_container[object_id]
1029
+ end
1030
+
1031
+ return catalog_container
1032
+ end
1033
+
965
1034
  if defined?(Redis.current) && object_id.present? && object_id.class == String && object_id.present?
966
1035
  stub_catalog = cache ? decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}")) : nil
967
1036
  object_hierarchy = decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Hierarchy"))
@@ -1221,7 +1290,7 @@ module ZuoraConnect
1221
1290
 
1222
1291
  def self.without_sticking
1223
1292
  if self.connection.respond_to?(:without_sticking)
1224
- self.connection.without_sticking do
1293
+ self.connection.without_sticking do
1225
1294
  yield
1226
1295
  end
1227
1296
  else