zuora_connect 0
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/MIT-LICENSE +20 -0
- data/Rakefile +38 -0
- data/app/assets/javascripts/hallway_wrapper/after.js +15 -0
- data/app/assets/javascripts/hallway_wrapper/before.js +2 -0
- data/app/assets/javascripts/zuora_connect/api/v1/app_instance.js +2 -0
- data/app/assets/javascripts/zuora_connect/application.js +13 -0
- data/app/assets/stylesheets/zuora_connect/api/v1/app_instance.css +4 -0
- data/app/assets/stylesheets/zuora_connect/application.css +15 -0
- data/app/controllers/zuora_connect/admin/tenant_controller.rb +11 -0
- data/app/controllers/zuora_connect/api/v1/app_instance_controller.rb +58 -0
- data/app/controllers/zuora_connect/application_controller.rb +8 -0
- data/app/controllers/zuora_connect/static_controller.rb +58 -0
- data/app/helpers/zuora_connect/api/v1/app_instance_helper.rb +4 -0
- data/app/helpers/zuora_connect/application_helper.rb +5 -0
- data/app/models/zuora_connect/app_instance.rb +5 -0
- data/app/models/zuora_connect/app_instance_base.rb +952 -0
- data/app/models/zuora_connect/login.rb +36 -0
- data/app/models/zuora_connect/telegraf.rb +93 -0
- data/app/views/layouts/zuora_connect/application.html.erb +14 -0
- data/app/views/sql/refresh_aggregate_table.txt +85 -0
- data/app/views/zuora_connect/static/invalid_app_instance_error.html.erb +65 -0
- data/app/views/zuora_connect/static/invalid_launch_request.html +65 -0
- data/app/views/zuora_connect/static/launch.html.erb +80 -0
- data/app/views/zuora_connect/static/session_error.html.erb +63 -0
- data/config/initializers/apartment.rb +95 -0
- data/config/initializers/aws.rb +2 -0
- data/config/initializers/elastic_apm.rb +25 -0
- data/config/initializers/object_method_hooks.rb +27 -0
- data/config/initializers/postgresql_adapter.rb +32 -0
- data/config/initializers/prometheus.rb +40 -0
- data/config/initializers/redis.rb +13 -0
- data/config/initializers/resque.rb +22 -0
- data/config/initializers/to_bool.rb +24 -0
- data/config/initializers/unicorn.rb +9 -0
- data/config/routes.rb +16 -0
- data/db/migrate/20100718151733_create_connect_app_instances.rb +9 -0
- data/db/migrate/20101024162319_add_tokens_to_app_instance.rb +6 -0
- data/db/migrate/20101024220705_add_token_to_app_instance.rb +5 -0
- data/db/migrate/20110131211919_add_sessions_table.rb +13 -0
- data/db/migrate/20110411200303_add_expiration_to_app_instance.rb +5 -0
- data/db/migrate/20110413191512_add_new_api_token.rb +5 -0
- data/db/migrate/20110503003602_add_catalog_data_to_app_instance.rb +6 -0
- data/db/migrate/20110503003603_add_catalog_mappings_to_app_instance.rb +5 -0
- data/db/migrate/20110503003604_catalog_default.rb +5 -0
- data/db/migrate/20180301052853_add_catalog_attempted_at.rb +5 -0
- data/db/migrate/20181206162339_add_fields_to_instance.rb +5 -0
- data/lib/metrics/influx/point_value.rb +79 -0
- data/lib/metrics/net.rb +218 -0
- data/lib/middleware/metrics_middleware.rb +134 -0
- data/lib/resque/additions.rb +53 -0
- data/lib/resque/dynamic_queues.rb +222 -0
- data/lib/resque/plugins/custom_logger.rb +46 -0
- data/lib/resque/self_lookup.rb +19 -0
- data/lib/resque/silence_done.rb +71 -0
- data/lib/tasks/zuora_connect_tasks.rake +24 -0
- data/lib/zuora_connect.rb +42 -0
- data/lib/zuora_connect/configuration.rb +53 -0
- data/lib/zuora_connect/controllers/helpers.rb +261 -0
- data/lib/zuora_connect/engine.rb +34 -0
- data/lib/zuora_connect/exceptions.rb +67 -0
- data/lib/zuora_connect/railtie.rb +63 -0
- data/lib/zuora_connect/version.rb +3 -0
- data/lib/zuora_connect/views/helpers.rb +9 -0
- data/test/controllers/zuora_connect/api/v1/app_instance_controller_test.rb +13 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/fixtures/zuora_connect/app_instances.yml +11 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/lib/generators/zuora_connect/datatable_generator_test.rb +16 -0
- data/test/models/zuora_connect/app_instance_test.rb +9 -0
- data/test/test_helper.rb +21 -0
- data/test/zuora_connect_test.rb +7 -0
- metadata +443 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4b69457446868cd3b97d81d5753a967f002d58dfc750c2a4cae9b880a590c741
|
4
|
+
data.tar.gz: e27a81b4e9f30562ff67632d57c3b9e798e76677b5b4ee7c2698473a349bb111
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cb57173d9c5ef615f65d42a1fb6034f47c9878840063d3d243b774ed036e3b30f82a86943b1cfccf9a6534d69849a47468a51b1978e6720a012320025120e9ae
|
7
|
+
data.tar.gz: 53cad727a3c349daf72ee6f3b77c6dfebfe658f41470feb2bc259c4cd5dda994f28f00291d8fa6b14e2feda38df2acc033fef79d8875c5a8c0e6acbef083581b
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Matthew Ingle
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
require 'apartment'
|
9
|
+
Apartment.db_migrate_tenants = false
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
11
|
+
rdoc.rdoc_dir = 'rdoc'
|
12
|
+
rdoc.title = 'Connect'
|
13
|
+
rdoc.options << '--line-numbers'
|
14
|
+
rdoc.rdoc_files.include('README.rdoc')
|
15
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
19
|
+
load 'rails/tasks/engine.rake'
|
20
|
+
|
21
|
+
|
22
|
+
load 'rails/tasks/statistics.rake'
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task default: :test
|
@@ -0,0 +1,15 @@
|
|
1
|
+
window.define = previousDefine;
|
2
|
+
|
3
|
+
// This'll be our "error service" for hallway
|
4
|
+
if (isHallway()) {
|
5
|
+
$( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
|
6
|
+
if ( jqxhr.status === 401) {
|
7
|
+
window.location.href = '/apps/newlogin.do?retURL=' + window.location.pathname;
|
8
|
+
}
|
9
|
+
});
|
10
|
+
}
|
11
|
+
|
12
|
+
function isHallway() {
|
13
|
+
var regex = new RegExp("^/services/");
|
14
|
+
return window.location.pathname.match(regex);
|
15
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
11
|
+
* file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_dependency "zuora_connect/application_controller"
|
2
|
+
|
3
|
+
module ZuoraConnect
|
4
|
+
class Api::V1::AppInstanceController < ApplicationController
|
5
|
+
|
6
|
+
def create
|
7
|
+
Apartment::Tenant.create(session['AppInstance'])
|
8
|
+
respond_to do |format|
|
9
|
+
format.json {render :json => "Created"}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def drop
|
14
|
+
instance_id = @appinstance.id
|
15
|
+
if session["#{instance_id}::destroy"] && ZuoraConnect::AppInstance.where(:id => instance_id).size != 0
|
16
|
+
if @appinstance.drop_instance
|
17
|
+
ZuoraConnect::AppInstance.destroy(instance_id)
|
18
|
+
msg = Apartment::Tenant.drop(instance_id)
|
19
|
+
|
20
|
+
respond_to do |format|
|
21
|
+
if msg.error_message.present?
|
22
|
+
format.json {render json: {"message" => msg.error_message}, status: :bad_request }
|
23
|
+
else
|
24
|
+
format.json {render json: {}, status: :ok}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
else
|
28
|
+
respond_to do |format|
|
29
|
+
format.json {render json: {"message" => @appinstance.drop_message}, status: :bad_request}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
else
|
33
|
+
respond_to do |format|
|
34
|
+
format.json { render json: { "message" => "Unauthorized"}, status: :unauthorized }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def status
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def cache_bust
|
45
|
+
if defined?(Redis.current)
|
46
|
+
Redis.current.del("AppInstance:#{@appinstance.id}")
|
47
|
+
respond_to do |format|
|
48
|
+
format.json {render json: {}, status: :ok}
|
49
|
+
end
|
50
|
+
else
|
51
|
+
respond_to do |format|
|
52
|
+
format.json {render json: {}, status: :bad_request}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ZuoraConnect
|
2
|
+
class StaticController < ApplicationController
|
3
|
+
before_action :authenticate_connect_app_request, :except => [:metrics, :health, :session_error, :invalid_app_instance_error, :initialize_app]
|
4
|
+
before_action :clear_connect_app_session, :only => [:metrics, :health, :session_error, :invalid_app_instance_error, :initialize_app]
|
5
|
+
after_action :persist_connect_app_session, :except => [:metrics, :health, :session_error, :invalid_app_instance_error, :initialize_app]
|
6
|
+
|
7
|
+
skip_before_action :verify_authenticity_token, :only => [:initialize_app]
|
8
|
+
|
9
|
+
def session_error
|
10
|
+
respond_to do |format|
|
11
|
+
format.html
|
12
|
+
format.json { render json: { message: "Session Error", status: 500 }, status: 500 }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def invalid_app_instance_error
|
17
|
+
respond_to do |format|
|
18
|
+
format.html
|
19
|
+
format.json {render json: { message: "Invalid App Instance", status: 500 }, status: 500 }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def metrics
|
24
|
+
type = params[:type].present? ? params[:type] : "versions"
|
25
|
+
render json: ZuoraConnect::AppInstance.get_metrics(type).to_json, status: 200
|
26
|
+
end
|
27
|
+
|
28
|
+
def health
|
29
|
+
render json: {
|
30
|
+
message: "Alive",
|
31
|
+
status: 200
|
32
|
+
}, status: 200
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize_app
|
36
|
+
begin
|
37
|
+
authenticate_connect_app_request
|
38
|
+
render json: {
|
39
|
+
message: "Success",
|
40
|
+
status: 200
|
41
|
+
}, status: 200
|
42
|
+
rescue
|
43
|
+
render json: {
|
44
|
+
message: "Failure initializing app instance",
|
45
|
+
status: 500
|
46
|
+
}, status: 500
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def clear_connect_app_session
|
53
|
+
Thread.current[:appinstance] = nil
|
54
|
+
request.session_options[:skip] = true
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,952 @@
|
|
1
|
+
module ZuoraConnect
|
2
|
+
require "uri"
|
3
|
+
class AppInstanceBase < ActiveRecord::Base
|
4
|
+
default_scope {select(ZuoraConnect::AppInstance.column_names.delete_if {|x| ["catalog_mapping", "catalog"].include?(x) }) }
|
5
|
+
after_initialize :init
|
6
|
+
after_create :initialize_redis_placeholder
|
7
|
+
before_destroy :prune_data
|
8
|
+
|
9
|
+
self.table_name = "zuora_connect_app_instances"
|
10
|
+
attr_accessor :options, :mode, :logins, :task_data, :last_refresh, :username, :password, :s3_client, :api_version, :drop_message, :new_session_message, :connect_user, :logitems
|
11
|
+
@@telegraf_host = nil
|
12
|
+
REFRESH_TIMEOUT = 2.minute #Used to determine how long to wait on current refresh call before executing another
|
13
|
+
INSTANCE_REFRESH_WINDOW = 1.hours #Used to set how how long till app starts attempting to refresh cached task connect data
|
14
|
+
INSTANCE_REDIS_CACHE_PERIOD = 24.hours #Used to determine how long to cached task data will live for
|
15
|
+
API_LIMIT_TIMEOUT = 2.minutes #Used to set the default for expiring timeout when api rate limiting is in effect
|
16
|
+
BLANK_OBJECT_ID_LOOKUP = 'BlankValueSupplied'
|
17
|
+
HOLDING_PATTERN_SLEEP = 5.seconds
|
18
|
+
CONNECT_COMMUNICATION_SLEEP= 5.seconds
|
19
|
+
|
20
|
+
def init
|
21
|
+
self.connect_user = 'Nobody'
|
22
|
+
self.logitems = {}
|
23
|
+
self.task_data = {}
|
24
|
+
self.options = Hash.new
|
25
|
+
self.logins = Hash.new
|
26
|
+
self.api_version = "v2"
|
27
|
+
self.attr_builder("timezone", ZuoraConnect.configuration.default_time_zone)
|
28
|
+
self.attr_builder("locale", ZuoraConnect.configuration.default_locale)
|
29
|
+
PaperTrail.whodunnit = "Backend" if defined?(PaperTrail)
|
30
|
+
if defined?(ElasticAPM)
|
31
|
+
ElasticAPM.set_user("Backend")
|
32
|
+
ElasticAPM.set_tag(:app_instance, self.id)
|
33
|
+
end
|
34
|
+
|
35
|
+
if INSTANCE_REFRESH_WINDOW > INSTANCE_REDIS_CACHE_PERIOD
|
36
|
+
raise "The instance refresh window cannot be greater than the instance cache period"
|
37
|
+
end
|
38
|
+
self.apartment_switch(nil, false)
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize_redis_placeholder
|
42
|
+
if defined?(Redis.current)
|
43
|
+
Redis.current.zrem("AppInstance:Deleted", id)
|
44
|
+
Redis.current.zadd("APILimits", 9999999999, "placeholder")
|
45
|
+
Redis.current.zadd("InstanceRefreshing", 9999999999, "placeholder")
|
46
|
+
end
|
47
|
+
if defined?(Resque.redis)
|
48
|
+
Resque.redis.zadd("PauseQueue", 9999999999, "placeholder")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def prune_data(id: self.id)
|
53
|
+
if defined?(Redis.current)
|
54
|
+
Redis.current.zadd("AppInstance:Deleted", Time.now.to_i, id)
|
55
|
+
Redis.current.del("AppInstance:#{id}")
|
56
|
+
Redis.current.zrem("APILimits", id)
|
57
|
+
Redis.current.zrem("InstanceRefreshing", id)
|
58
|
+
end
|
59
|
+
if defined?(Resque.redis)
|
60
|
+
Resque.redis.zrem("PauseQueue", id)
|
61
|
+
end
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
|
65
|
+
def apartment_switch(method = nil, migrate = false)
|
66
|
+
switch_count ||= 0
|
67
|
+
if self.persisted?
|
68
|
+
begin
|
69
|
+
Apartment::Tenant.switch!(self.id)
|
70
|
+
rescue Apartment::TenantNotFound => ex
|
71
|
+
sleep(2)
|
72
|
+
begin
|
73
|
+
Apartment::Tenant.create(self.id.to_s)
|
74
|
+
rescue Apartment::TenantExists => ex
|
75
|
+
end
|
76
|
+
if (switch_count += 1) < 2
|
77
|
+
retry
|
78
|
+
else
|
79
|
+
raise
|
80
|
+
end
|
81
|
+
end
|
82
|
+
if migrate && ActiveRecord::Migrator.needs_migration?
|
83
|
+
Apartment::Migrator.migrate(self.id)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
Thread.current[:appinstance] = self
|
87
|
+
end
|
88
|
+
|
89
|
+
def new_session(session: self.data_lookup, username: self.access_token, password: self.refresh_token, holding_pattern: false, log_level: Logger::DEBUG)
|
90
|
+
self.api_version = "v2"
|
91
|
+
self.username = username
|
92
|
+
self.password = password
|
93
|
+
self.last_refresh = session["#{self.id}::last_refresh"]
|
94
|
+
self.connect_user = session["#{self.id}::user::email"] if session["#{self.id}::user::email"].present?
|
95
|
+
PaperTrail.whodunnit = self.connect_user if defined?(PaperTrail)
|
96
|
+
ElasticAPM.set_user(self.connect_user) if defined?(ElasticAPM)
|
97
|
+
recoverable_session = false
|
98
|
+
|
99
|
+
## DEV MODE TASK DATA MOCKUP
|
100
|
+
if ZuoraConnect.configuration.mode != "Production"
|
101
|
+
mock_task_data = {
|
102
|
+
"mode" => ZuoraConnect.configuration.dev_mode_mode
|
103
|
+
}
|
104
|
+
|
105
|
+
case ZuoraConnect.configuration.dev_mode_options.class
|
106
|
+
when Hash
|
107
|
+
self.options = ZuoraConnect.configuration.dev_mode_options
|
108
|
+
when Array
|
109
|
+
mock_task_data["options"] = ZuoraConnect.configuration.dev_mode_options
|
110
|
+
end
|
111
|
+
|
112
|
+
ZuoraConnect.configuration.dev_mode_logins.each do |k,v|
|
113
|
+
v = v.merge({"entities": [] }) if !v.keys.include?("entities")
|
114
|
+
mock_task_data[k] = v
|
115
|
+
end
|
116
|
+
|
117
|
+
self.build_task(task_data: mock_task_data, session: session)
|
118
|
+
else
|
119
|
+
time_expire = (session["#{self.id}::last_refresh"] || Time.now).to_i - INSTANCE_REFRESH_WINDOW.ago.to_i
|
120
|
+
|
121
|
+
if session.empty?
|
122
|
+
self.new_session_message = "REFRESHING - Session Empty"
|
123
|
+
Rails.logger.add(log_level, self.new_session_message)
|
124
|
+
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
125
|
+
self.refresh(session: session)
|
126
|
+
|
127
|
+
elsif (self.id != session["appInstance"].to_i)
|
128
|
+
self.new_session_message = "REFRESHING - AppInstance ID(#{self.id}) does not match session id(#{session["appInstance"].to_i})"
|
129
|
+
Rails.logger.add(log_level, self.new_session_message)
|
130
|
+
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
131
|
+
self.refresh(session: session)
|
132
|
+
|
133
|
+
elsif session["#{self.id}::task_data"].blank?
|
134
|
+
self.new_session_message = "REFRESHING - Task Data Blank"
|
135
|
+
Rails.logger.add(log_level, self.new_session_message)
|
136
|
+
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
137
|
+
self.refresh(session: session)
|
138
|
+
|
139
|
+
elsif session["#{self.id}::last_refresh"].blank?
|
140
|
+
self.new_session_message = "REFRESHING - No Time on Cookie"
|
141
|
+
recoverable_session = true
|
142
|
+
Rails.logger.add(log_level, self.new_session_message)
|
143
|
+
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
144
|
+
self.refresh(session: session)
|
145
|
+
|
146
|
+
# If the cache is expired and we can aquire a refresh lock
|
147
|
+
elsif (session["#{self.id}::last_refresh"].to_i < INSTANCE_REFRESH_WINDOW.ago.to_i) && self.mark_for_refresh
|
148
|
+
self.new_session_message = "REFRESHING - Session Old by #{time_expire.abs} second"
|
149
|
+
recoverable_session = true
|
150
|
+
Rails.logger.add(log_level, self.new_session_message)
|
151
|
+
self.refresh(session: session)
|
152
|
+
|
153
|
+
else
|
154
|
+
if time_expire < 0
|
155
|
+
self.new_session_message = ["REBUILDING - Expired by #{time_expire} seconds", self.marked_for_refresh? ? " cache updating as of #{self.reset_mark_refreshed_at} seconds ago" : nil].compact.join(',')
|
156
|
+
else
|
157
|
+
self.new_session_message = "REBUILDING - Expires in #{time_expire} seconds"
|
158
|
+
end
|
159
|
+
Rails.logger.add(log_level, self.new_session_message)
|
160
|
+
self.build_task(task_data: session["#{self.id}::task_data"], session: session)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
return self
|
164
|
+
rescue ZuoraConnect::Exceptions::HoldingPattern => ex
|
165
|
+
while self.marked_for_refresh?
|
166
|
+
Rails.logger.info("Holding - Expires in #{self.reset_mark_expires_at}. '#{self.new_session_message}'")
|
167
|
+
sleep(HOLDING_PATTERN_SLEEP)
|
168
|
+
end
|
169
|
+
self.reload_attributes([:refresh_token, :oauth_expires_at, :access_token])
|
170
|
+
session = self.data_lookup(session: session)
|
171
|
+
retry
|
172
|
+
rescue => ex
|
173
|
+
if recoverable_session
|
174
|
+
Rails.logger.error("REBUILDING - Using backup expired cache")
|
175
|
+
self.build_task(task_data: session["#{self.id}::task_data"], session: session)
|
176
|
+
return self
|
177
|
+
else
|
178
|
+
raise
|
179
|
+
end
|
180
|
+
ensure
|
181
|
+
begin
|
182
|
+
I18n.locale = self.locale
|
183
|
+
rescue I18n::InvalidLocale => ex
|
184
|
+
Rails.logger.debug("Invalid Locale: #{ex.message}")
|
185
|
+
end
|
186
|
+
Time.zone = self.timezone
|
187
|
+
tenants = self.task_data.dig('tenant_ids') || []
|
188
|
+
organizations = self.task_data.dig('organizations') || []
|
189
|
+
if defined?(ElasticAPM)
|
190
|
+
ElasticAPM.set_tag(:tenant_id, tenants.first)
|
191
|
+
ElasticAPM.set_tag(:organization, organizations.first)
|
192
|
+
end
|
193
|
+
self.logitem(item: {tenant_ids: tenants, organization: organizations})
|
194
|
+
self.update_column(:name, self.task_data.dig('name')) if ZuoraConnect::AppInstance.column_names.include?('name') && self.task_data.dig('name') != self.name
|
195
|
+
end
|
196
|
+
|
197
|
+
def refresh(session: {}, session_fallback: false)
|
198
|
+
refresh_count ||= 0
|
199
|
+
start = Time.now
|
200
|
+
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
|
201
|
+
response_time = Time.now - start
|
202
|
+
|
203
|
+
Rails.logger.debug("[#{self.id}] REFRESH TASK - Connect Task Info Request Time #{response_time.round(2).to_s}")
|
204
|
+
if response.code == 200
|
205
|
+
self.build_task(task_data: JSON.parse(response.body), session: session)
|
206
|
+
self.last_refresh = Time.now.to_i
|
207
|
+
self.cache_app_instance
|
208
|
+
self.reset_mark_for_refresh
|
209
|
+
else
|
210
|
+
Rails.logger.fatal("[#{self.id}] REFRESH TASK - Failed Code #{response.code}")
|
211
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
212
|
+
end
|
213
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
214
|
+
if (refresh_count += 1) < 3
|
215
|
+
Rails.logger.info("[#{self.id}] REFRESH TASK - #{ex.class} Retrying(#{refresh_count})")
|
216
|
+
retry
|
217
|
+
else
|
218
|
+
Rails.logger.fatal("[#{self.id}] REFRESH TASK - #{ex.class} Failed #{refresh_count}x")
|
219
|
+
raise
|
220
|
+
end
|
221
|
+
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
222
|
+
if (refresh_count += 1) < 3
|
223
|
+
Rails.logger.info("[#{self.id}] REFRESH TASK - Failed Retrying(#{refresh_count})")
|
224
|
+
if ex.code == 401
|
225
|
+
self.refresh_oauth
|
226
|
+
end
|
227
|
+
retry
|
228
|
+
else
|
229
|
+
Rails.logger.fatal("[#{self.id}] REFRESH TASK - Failed #{refresh_count}x")
|
230
|
+
raise
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
#### START Metrics Mathods ####
|
235
|
+
def logitem(item: {}, reset: false)
|
236
|
+
self.logitems = {} if self.logitems.class != Hash
|
237
|
+
if item.class == Hash
|
238
|
+
self.logitems = reset ? item : self.logitems.merge(item)
|
239
|
+
end
|
240
|
+
Thread.current[:appinstance] = self
|
241
|
+
end
|
242
|
+
|
243
|
+
def self.write_to_telegraf(*args)
|
244
|
+
if ZuoraConnect.configuration.enable_metrics
|
245
|
+
@@telegraf_host = ZuoraConnect::Telegraf.new() if @@telegraf_host == nil
|
246
|
+
return @@telegraf_host.write(*args)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def self.get_metrics(type)
|
251
|
+
@data = {}
|
252
|
+
|
253
|
+
if type == "versions"
|
254
|
+
@data = {
|
255
|
+
app_name: ZuoraConnect::Telegraf.app_name,
|
256
|
+
url: "dummy",
|
257
|
+
Version_Gem: ZuoraConnect::VERSION,
|
258
|
+
Version_Zuora: ZuoraAPI::VERSION ,
|
259
|
+
Version_Ruby: RUBY_VERSION,
|
260
|
+
Version_Rails: Rails.version,
|
261
|
+
hold: 1
|
262
|
+
}
|
263
|
+
elsif type == "stats"
|
264
|
+
begin
|
265
|
+
Resque.redis.ping
|
266
|
+
@resque = Resque.info
|
267
|
+
@data = {
|
268
|
+
app_name: ZuoraConnect::Telegraf.app_name,
|
269
|
+
url: "dummy",
|
270
|
+
Resque:{
|
271
|
+
Jobs_Finished: @resque[:processed] ,
|
272
|
+
Jobs_Failed: @resque[:failed],
|
273
|
+
Jobs_Pending: @resque[:pending],
|
274
|
+
Workers_Active: @resque[:working],
|
275
|
+
Workers_Total: @resque[:workers]
|
276
|
+
}
|
277
|
+
}
|
278
|
+
rescue
|
279
|
+
end
|
280
|
+
end
|
281
|
+
return @data
|
282
|
+
end
|
283
|
+
#### END Task Mathods ####
|
284
|
+
|
285
|
+
#### START Task Mathods ####
|
286
|
+
def build_task(task_data: {}, session: {})
|
287
|
+
session = {} if session.blank?
|
288
|
+
self.task_data = task_data
|
289
|
+
self.mode = self.task_data["mode"]
|
290
|
+
self.task_data.each do |k,v|
|
291
|
+
if k.match(/^(.*)_login$/)
|
292
|
+
tmp = ZuoraConnect::Login.new(v)
|
293
|
+
if v["tenant_type"] == "Zuora"
|
294
|
+
if tmp.entities.size > 0
|
295
|
+
tmp.entities.each do |value|
|
296
|
+
entity_id = value["id"]
|
297
|
+
tmp.client(entity_id).current_session = session["#{self.id}::#{k}::#{entity_id}:current_session"] if session["#{self.id}::#{k}::#{entity_id}:current_session"]
|
298
|
+
tmp.client(entity_id).bearer_token = session["#{self.id}::#{k}::#{entity_id}:bearer_token"] if session["#{self.id}::#{k}::#{entity_id}:bearer_token"]
|
299
|
+
tmp.client(entity_id).oauth_session_expires_at = session["#{self.id}::#{k}::#{entity_id}:oauth_session_expires_at"] if session["#{self.id}::#{k}::#{entity_id}:oauth_session_expires_at"]
|
300
|
+
end
|
301
|
+
else
|
302
|
+
tmp.client.current_session = session["#{self.id}::#{k}:current_session"] if session["#{self.id}::#{k}:current_session"]
|
303
|
+
tmp.client.bearer_token = session["#{self.id}::#{k}:bearer_token"] if session["#{self.id}::#{k}:bearer_token"] && tmp.client.respond_to?(:bearer_token) ## need incase session id goes from basic to aouth in same redis store
|
304
|
+
tmp.client.oauth_session_expires_at = session["#{self.id}::#{k}:oauth_session_expires_at"] if session["#{self.id}::#{k}:oauth_session_expires_at"] && tmp.client.respond_to?(:oauth_session_expires_at)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
self.logins[k] = tmp
|
308
|
+
self.attr_builder(k, @logins[k])
|
309
|
+
elsif k == "options"
|
310
|
+
v.each do |opt|
|
311
|
+
self.options[opt["config_name"]] = opt
|
312
|
+
end
|
313
|
+
elsif k == "user_settings"
|
314
|
+
self.timezone = v["timezone"]
|
315
|
+
self.locale = v["local"]
|
316
|
+
end
|
317
|
+
end
|
318
|
+
rescue => ex
|
319
|
+
Rails.logger.error("Task Data: #{task_data}") if task_data.present?
|
320
|
+
Rails.logger.error("Task Session: #{session.to_h}") if session.present?
|
321
|
+
raise
|
322
|
+
end
|
323
|
+
|
324
|
+
def updateOption(optionId, value)
|
325
|
+
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/application_options/#{optionId}/edit?value=#{value}",:body => {:access_token => self.username})
|
326
|
+
end
|
327
|
+
|
328
|
+
#This can update an existing login, add a new login, change to another existing login
|
329
|
+
#EXAMPLE: {"name": "ftp_login_14","username": "ftplogin7","tenant_type": "Custom","password": "test2","url": "www.ftp.com","custom_data": { "path": "/var/usr/test"}}
|
330
|
+
def update_logins(options)
|
331
|
+
update_login_count ||= 0
|
332
|
+
response = HTTParty.post(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}/logins",:body => {:access_token => self.username}.merge(options))
|
333
|
+
parsed_json = JSON.parse(response.body)
|
334
|
+
if response.code == 200
|
335
|
+
if defined?(Redis.current)
|
336
|
+
self.build_task(task_data: parsed_json, session: self.data_lookup)
|
337
|
+
self.last_refresh = Time.now.to_i
|
338
|
+
self.cache_app_instance
|
339
|
+
end
|
340
|
+
return parsed_json
|
341
|
+
elsif response.code == 400
|
342
|
+
raise ZuoraConnect::Exceptions::APIError.new(message: parsed_json['errors'].join(' '), response: response.body, code: response.code)
|
343
|
+
else
|
344
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
345
|
+
end
|
346
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
347
|
+
if (update_login_count += 1) < 3
|
348
|
+
retry
|
349
|
+
else
|
350
|
+
raise
|
351
|
+
end
|
352
|
+
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
353
|
+
if (update_login_count += 1) < 3
|
354
|
+
if ex.code == 401
|
355
|
+
self.refresh_oauth
|
356
|
+
end
|
357
|
+
retry
|
358
|
+
else
|
359
|
+
raise
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def update_task(options)
|
364
|
+
update_task_count ||= 0
|
365
|
+
response = HTTParty.post(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}/update_task",:body => {:access_token => self.username}.merge(options))
|
366
|
+
parsed_json = JSON.parse(response.body)
|
367
|
+
if response.code == 200
|
368
|
+
return parsed_json
|
369
|
+
elsif response.code == 400
|
370
|
+
raise ZuoraConnect::Exceptions::APIError.new(message: parsed_json['errors'].join(' '), response: response.body, code: response.code)
|
371
|
+
else
|
372
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
373
|
+
end
|
374
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
375
|
+
if (update_task_count += 1) < 3
|
376
|
+
retry
|
377
|
+
else
|
378
|
+
raise
|
379
|
+
end
|
380
|
+
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
381
|
+
if (update_task_count += 1) < 3
|
382
|
+
if ex.code == 401
|
383
|
+
self.refresh_oauth
|
384
|
+
end
|
385
|
+
retry
|
386
|
+
else
|
387
|
+
raise
|
388
|
+
end
|
389
|
+
end
|
390
|
+
#### END Task Mathods ####
|
391
|
+
|
392
|
+
#### START Connect OAUTH methods ####
|
393
|
+
def check_oauth_state(method)
|
394
|
+
#Refresh token if already expired
|
395
|
+
if self.oauth_expired?
|
396
|
+
Rails.logger.debug("[#{self.id}] Before '#{method}' method, Oauth expired")
|
397
|
+
self.refresh_oauth
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def oauth_expired?
|
402
|
+
return self.oauth_expires_at.present? ? (self.oauth_expires_at < Time.now.utc) : true
|
403
|
+
end
|
404
|
+
|
405
|
+
def refresh_oauth
|
406
|
+
refresh_oauth_count ||= 0
|
407
|
+
start = Time.now
|
408
|
+
params = {
|
409
|
+
:grant_type => "refresh_token",
|
410
|
+
:redirect_uri => ZuoraConnect.configuration.oauth_client_redirect_uri,
|
411
|
+
:refresh_token => self.refresh_token
|
412
|
+
}
|
413
|
+
response = HTTParty.post("#{ZuoraConnect.configuration.url}/oauth/token",:body => params)
|
414
|
+
response_time = Time.now - start
|
415
|
+
Rails.logger.info("[#{self.id}] REFRESH OAUTH - In #{response_time.round(2).to_s}")
|
416
|
+
|
417
|
+
if response.code == 200
|
418
|
+
response_body = JSON.parse(response.body)
|
419
|
+
|
420
|
+
self.refresh_token = response_body["refresh_token"]
|
421
|
+
self.access_token = response_body["access_token"]
|
422
|
+
self.oauth_expires_at = Time.at(response_body["created_at"].to_i) + response_body["expires_in"].seconds
|
423
|
+
self.save(:validate => false)
|
424
|
+
else
|
425
|
+
Rails.logger.fatal("[#{self.id}] REFRESH OAUTH - Failed Code #{response.code}")
|
426
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Refreshing Access Token", response.body, response.code)
|
427
|
+
end
|
428
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
429
|
+
if (refresh_oauth_count += 1) < 3
|
430
|
+
Rails.logger.info("[#{self.id}] REFRESH OAUTH - #{ex.class} Retrying(#{refresh_oauth_count})")
|
431
|
+
retry
|
432
|
+
else
|
433
|
+
Rails.logger.fatal("[#{self.id}] REFRESH OAUTH - #{ex.class} Failed #{refresh_oauth_count}x")
|
434
|
+
raise
|
435
|
+
end
|
436
|
+
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
437
|
+
sleep(CONNECT_COMMUNICATION_SLEEP)
|
438
|
+
self.reload_attributes([:refresh_token, :oauth_expires_at, :access_token]) #Reload only the refresh token for retry
|
439
|
+
|
440
|
+
#After reload, if nolonger expired return
|
441
|
+
return if !self.oauth_expired?
|
442
|
+
|
443
|
+
if (refresh_oauth_count += 1) < 3
|
444
|
+
Rails.logger.info("[#{self.id}] REFRESH OAUTH - Failed Retrying(#{refresh_oauth_count})")
|
445
|
+
retry
|
446
|
+
else
|
447
|
+
Rails.logger.fatal("[#{self.id}] REFRESH OAUTH - Failed #{refresh_oauth_count}x")
|
448
|
+
raise
|
449
|
+
end
|
450
|
+
end
|
451
|
+
#### END Connect OAUTH methods ####
|
452
|
+
|
453
|
+
#### START AppInstance Temporary Persistance Methods ####
|
454
|
+
def marked_for_refresh?
|
455
|
+
if defined?(Redis.current)
|
456
|
+
Redis.current.zremrangebyscore("InstanceRefreshing", "0", "(#{Time.now.to_i}")
|
457
|
+
return Redis.current.zscore("InstanceRefreshing", self.id).present?
|
458
|
+
else
|
459
|
+
return false
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
def reset_mark_for_refresh
|
464
|
+
Redis.current.zrem("InstanceRefreshing", self.id) if defined?(Redis.current)
|
465
|
+
end
|
466
|
+
|
467
|
+
def reset_mark_refreshed_at
|
468
|
+
return defined?(Redis.current) ? REFRESH_TIMEOUT.to_i - reset_mark_expires_at : 0
|
469
|
+
end
|
470
|
+
|
471
|
+
def reset_mark_expires_at
|
472
|
+
if defined?(Redis.current)
|
473
|
+
refresh_time = Redis.current.zscore("InstanceRefreshing", self.id)
|
474
|
+
return refresh_time.present? ? (refresh_time - Time.now.to_i).round(0) : 0
|
475
|
+
else
|
476
|
+
return 0
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
def mark_for_refresh
|
481
|
+
return defined?(Redis.current) ? Redis.current.zadd("InstanceRefreshing", Time.now.to_i + REFRESH_TIMEOUT.to_i, self.id, {:nx => true}) : true
|
482
|
+
end
|
483
|
+
|
484
|
+
def data_lookup(session: {})
|
485
|
+
if defined?(Redis.current)
|
486
|
+
begin
|
487
|
+
redis_get_command ||= 0
|
488
|
+
cached_instance = Redis.current.get("AppInstance:#{self.id}")
|
489
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
490
|
+
if (redis_get_command += 1) < 3
|
491
|
+
retry
|
492
|
+
else
|
493
|
+
raise
|
494
|
+
end
|
495
|
+
end
|
496
|
+
if cached_instance.blank?
|
497
|
+
Rails.logger.debug("[#{self.id}] Cached AppInstance Missing")
|
498
|
+
return session
|
499
|
+
else
|
500
|
+
Rails.logger.debug("[#{self.id}] Cached AppInstance Found")
|
501
|
+
return decrypt_data(data: cached_instance, rescue_return: session).merge(session)
|
502
|
+
end
|
503
|
+
else
|
504
|
+
return session
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
def cache_app_instance
|
509
|
+
if defined?(Redis.current)
|
510
|
+
#Task data must be present and the last refresh cannot be old. We dont want to overwite new cache data with old
|
511
|
+
if self.task_data.present? && (self.last_refresh.to_i > INSTANCE_REFRESH_WINDOW.ago.to_i)
|
512
|
+
Rails.logger.debug("[#{self.id}] Caching AppInstance")
|
513
|
+
Redis.current.setex("AppInstance:#{self.id}", INSTANCE_REDIS_CACHE_PERIOD.to_i, self.encrypt_data(data: self.save_data))
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
def save_data(session = Hash.new)
|
519
|
+
self.logins.each do |key, login|
|
520
|
+
if login.tenant_type == "Zuora"
|
521
|
+
if login.available_entities.size > 1 && Rails.application.config.session_store != ActionDispatch::Session::CookieStore
|
522
|
+
login.available_entities.each do |entity_key|
|
523
|
+
session["#{self.id}::#{key}::#{entity_key}:current_session"] = login.client(entity_key).current_session if login.client.respond_to?(:current_session)
|
524
|
+
session["#{self.id}::#{key}::#{entity_key}:bearer_token"] = login.client(entity_key).bearer_token if login.client.respond_to?(:bearer_token)
|
525
|
+
session["#{self.id}::#{key}::#{entity_key}:oauth_session_expires_at"] = login.client(entity_key).oauth_session_expires_at if login.client.respond_to?(:oauth_session_expires_at)
|
526
|
+
end
|
527
|
+
else
|
528
|
+
session["#{self.id}::#{key}:current_session"] = login.client.current_session if login.client.respond_to?(:current_session)
|
529
|
+
session["#{self.id}::#{key}:bearer_token"] = login.client.bearer_token if login.client.respond_to?(:bearer_token)
|
530
|
+
session["#{self.id}::#{key}:oauth_session_expires_at"] = login.client.oauth_session_expires_at if login.client.respond_to?(:oauth_session_expires_at)
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
session["#{self.id}::task_data"] = self.task_data
|
536
|
+
|
537
|
+
#Redis is not defined strip out old data
|
538
|
+
if !defined?(Redis.current)
|
539
|
+
session["#{self.id}::task_data"].delete('applications')
|
540
|
+
session["#{self.id}::task_data"].delete('tenant_ids')
|
541
|
+
session["#{self.id}::task_data"].delete('organizations')
|
542
|
+
session["#{self.id}::task_data"].select {|k,v| k.include?('login') && v['tenant_type'] == 'Zuora'}.each do |login_key, login_data|
|
543
|
+
session["#{self.id}::task_data"][login_key]['entities'] = (login_data.dig('entities') || []).map {|entity| entity.slice('id', 'tenantId')}
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
session["#{self.id}::last_refresh"] = self.last_refresh
|
548
|
+
session["appInstance"] = self.id
|
549
|
+
return session
|
550
|
+
end
|
551
|
+
|
552
|
+
def encryptor
|
553
|
+
# Default values for Rails 4 apps
|
554
|
+
key_iter_num, key_size, salt, signed_salt = [1000, 64, "encrypted cookie", "signed encrypted cookie"]
|
555
|
+
raise ZuoraConnect::Exceptions::Error.new("'secret_key_base' is not set for rails environment '#{Rails.env}'. Please set in secrets file.") if Rails.application.secrets.secret_key_base.blank?
|
556
|
+
key_generator = ActiveSupport::KeyGenerator.new(Rails.application.secrets.secret_key_base, iterations: key_iter_num)
|
557
|
+
secret, sign_secret = [key_generator.generate_key(salt, 32), key_generator.generate_key(signed_salt)]
|
558
|
+
return ActiveSupport::MessageEncryptor.new(secret, sign_secret)
|
559
|
+
end
|
560
|
+
|
561
|
+
def decrypt_data(data: nil, rescue_return: nil, log_fatal: true)
|
562
|
+
return data if data.blank?
|
563
|
+
if Rails.env == 'development'
|
564
|
+
begin
|
565
|
+
return JSON.parse(data)
|
566
|
+
rescue JSON::ParserError => ex
|
567
|
+
return data
|
568
|
+
end
|
569
|
+
else
|
570
|
+
begin
|
571
|
+
return JSON.parse(encryptor.decrypt_and_verify(CGI::unescape(data)))
|
572
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature => ex
|
573
|
+
Rails.logger.add(Logger::FATAL, 'Error Decrypting') if log_fatal
|
574
|
+
return rescue_return
|
575
|
+
rescue JSON::ParserError => ex
|
576
|
+
return encryptor.decrypt_and_verify(CGI::unescape(data))
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
def encrypt_data(data: nil)
|
582
|
+
return data if data.blank?
|
583
|
+
if Rails.env == 'development'
|
584
|
+
return data.to_json
|
585
|
+
else
|
586
|
+
return encryptor.encrypt_and_sign(data.to_json)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
#### END AppInstance Temporary Persistance Methods ####
|
590
|
+
|
591
|
+
### START Resque Helping Methods ####
|
592
|
+
def api_limit(start: true, time: API_LIMIT_TIMEOUT.to_i)
|
593
|
+
if start
|
594
|
+
Redis.current.zadd("APILimits", Time.now.to_i + time, self.id)
|
595
|
+
else
|
596
|
+
Redis.current.zrem("APILimits", self.id)
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
def api_limit?
|
601
|
+
Redis.current.zremrangebyscore("APILimits", "0", "(#{Time.now.to_i}")
|
602
|
+
return Redis.current.zscore("APILimits", self.id).present?
|
603
|
+
end
|
604
|
+
|
605
|
+
def queue_paused?
|
606
|
+
Resque.redis.zremrangebyscore("PauseQueue", "0", "(#{Time.now.to_i}")
|
607
|
+
return Resque.redis.zrange("PauseQueue", 0, -1).map {|key| key.split("__")[0]}.include?(self.id.to_s)
|
608
|
+
end
|
609
|
+
|
610
|
+
def queue_pause(time: nil, current_user: 'Default')
|
611
|
+
key = "#{self.id}__#{current_user}"
|
612
|
+
if time.present?
|
613
|
+
raise "Time must be integer of seconds instead of #{time.class}." if !['Integer', 'Fixnum'].include?(time.class.to_s)
|
614
|
+
Resque.redis.zadd("PauseQueue", Time.now.to_i + time, key)
|
615
|
+
else
|
616
|
+
Resque.redis.zadd("PauseQueue", 9999999999, key)
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
def queue_start(current_user: 'Default')
|
621
|
+
paused_user = Resque.redis.zrange("PauseQueue", 0, -1).map {|key| key.split("__")[0] == "#{self.id}" ? key.split("__")[1] : nil}.compact.first
|
622
|
+
if paused_user == current_user || paused_user.blank?
|
623
|
+
Resque.redis.zrem("PauseQueue", "#{self.id}__#{paused_user}")
|
624
|
+
else
|
625
|
+
raise "Can only unpause for user #{paused_user}."
|
626
|
+
end
|
627
|
+
end
|
628
|
+
### END Resque Helping Methods ####
|
629
|
+
|
630
|
+
### START Catalog Helping Methods #####
|
631
|
+
def get_catalog(page_size: 5, zuora_login: self.login_lookup(type: "Zuora").first, entity_id: nil)
|
632
|
+
self.update_column(:catalog_update_attempt_at, Time.now.utc)
|
633
|
+
|
634
|
+
entity_reference = entity_id.blank? ? 'Default' : entity_id
|
635
|
+
Rails.logger.debug("Fetch Catalog")
|
636
|
+
Rails.logger.debug("Zuora Entity: #{entity_id.blank? ? 'default' : entity_id}")
|
637
|
+
|
638
|
+
login = zuora_login.client(entity_reference)
|
639
|
+
|
640
|
+
old_logger = ActiveRecord::Base.logger
|
641
|
+
ActiveRecord::Base.logger = nil
|
642
|
+
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog" = jsonb_set("catalog", \'{tmp}\', \'{}\'), "catalog_mapping" = jsonb_set("catalog_mapping", \'{tmp}\', \'{}\') where "id" = %{id}' % {:id => self.id})
|
643
|
+
|
644
|
+
response = {'nextPage' => login.rest_endpoint("catalog/products?pageSize=#{page_size}")}
|
645
|
+
while !response["nextPage"].blank?
|
646
|
+
url = login.rest_endpoint(response["nextPage"].split('/v1/').last)
|
647
|
+
Rails.logger.debug("Fetch Catalog URL #{url}")
|
648
|
+
output_json, response = login.rest_call(:debug => false, :url => url, :errors => [ZuoraAPI::Exceptions::ZuoraAPISessionError], :timeout_retry => true)
|
649
|
+
Rails.logger.debug("Fetch Catalog Response Code #{response.code}")
|
650
|
+
|
651
|
+
if !output_json['success'] =~ (/(true|t|yes|y|1)$/i) || output_json['success'].class != TrueClass
|
652
|
+
Rails.logger.error("Fetch Catalog DATA #{output_json.to_json}")
|
653
|
+
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error Getting Catalog: #{output_json}")
|
654
|
+
end
|
655
|
+
|
656
|
+
output_json["products"].each do |product|
|
657
|
+
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog_mapping" = jsonb_set("catalog_mapping", \'{tmp, %s}\', \'%s\') where "id" = %s' % [product["id"], {"productId" => product["id"]}.to_json.gsub("'", "''"), self.id])
|
658
|
+
rateplans = {}
|
659
|
+
|
660
|
+
product["productRatePlans"].each do |rateplan|
|
661
|
+
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog_mapping" = jsonb_set("catalog_mapping", \'{tmp, %s}\', \'%s\') where "id" = %s' % [rateplan["id"], {"productId" => product["id"], "productRatePlanId" => rateplan["id"]}.to_json.gsub("'", "''"), self.id])
|
662
|
+
charges = {}
|
663
|
+
|
664
|
+
rateplan["productRatePlanCharges"].each do |charge|
|
665
|
+
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog_mapping" = jsonb_set("catalog_mapping", \'{tmp, %s}\', \'%s\') where "id" = %s' % [charge["id"], {"productId" => product["id"], "productRatePlanId" => rateplan["id"], "productRatePlanChargeId" => charge["id"]}.to_json.gsub("'", "''"), self.id])
|
666
|
+
|
667
|
+
charges[charge["id"]] = charge.merge({"productId" => product["id"], "productName" => product["name"], "productRatePlanId" => rateplan["id"], "productRatePlanName" => rateplan["name"] })
|
668
|
+
end
|
669
|
+
|
670
|
+
rateplan["productRatePlanCharges"] = charges
|
671
|
+
rateplans[rateplan["id"]] = rateplan.merge({"productId" => product["id"], "productName" => product["name"]})
|
672
|
+
end
|
673
|
+
product["productRatePlans"] = rateplans
|
674
|
+
|
675
|
+
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog" = jsonb_set("catalog", \'{tmp, %s}\', \'%s\') where "id" = %s' % [product["id"], product.to_json.gsub("'", "''"), self.id])
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
# Move from tmp to actual
|
680
|
+
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog" = jsonb_set("catalog", \'{%{entity}}\', "catalog" #> \'{tmp}\'), "catalog_mapping" = jsonb_set("catalog_mapping", \'{%{entity}}\', "catalog_mapping" #> \'{tmp}\') where "id" = %{id}' % {:entity => entity_reference, :id => self.id})
|
681
|
+
if defined?(Redis.current)
|
682
|
+
catalog_keys = Redis.current.smembers("Catalog:#{self.id}:Keys")
|
683
|
+
Redis.current.del(catalog_keys.push("Catalog:#{self.id}:Keys"))
|
684
|
+
end
|
685
|
+
# Clear tmp holder
|
686
|
+
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog" = jsonb_set("catalog", \'{tmp}\', \'{}\'), "catalog_mapping" = jsonb_set("catalog_mapping", \'{tmp}\', \'{}\') where "id" = %{id}' % {:id => self.id})
|
687
|
+
|
688
|
+
ActiveRecord::Base.logger = old_logger
|
689
|
+
self.update_column(:catalog_updated_at, Time.now.utc)
|
690
|
+
self.touch
|
691
|
+
|
692
|
+
# DO NOT RETURN CATALOG. THIS IS NOT SCALABLE WITH LARGE CATALOGS. USE THE CATALOG_LOOKUP method provided
|
693
|
+
return true
|
694
|
+
end
|
695
|
+
|
696
|
+
def catalog_outdated?(time: Time.now - 12.hours)
|
697
|
+
return self.catalog_updated_at.blank? || (self.catalog_updated_at < time)
|
698
|
+
end
|
699
|
+
|
700
|
+
def catalog_loaded?
|
701
|
+
return ActiveRecord::Base.connection.execute('SELECT id FROM "public"."zuora_connect_app_instances" WHERE "id" = %s AND catalog = \'{}\' LIMIT 1' % [self.id]).first.nil?
|
702
|
+
end
|
703
|
+
|
704
|
+
# Catalog lookup provides method to lookup zuora catalog efficiently.
|
705
|
+
# entity_id: If the using catalog json be field to store multiple entity product catalogs.
|
706
|
+
# object: The Object class desired to be returned. Available [:product, :rateplan, :charge]
|
707
|
+
# object_id: The id or id's of the object/objects to be returned.
|
708
|
+
# child_objects: Whether to include child objects of the object in question.
|
709
|
+
# cache: Store individual "1" object lookup in redis for caching.
|
710
|
+
def catalog_lookup(entity_id: nil, object: :product, object_id: nil, child_objects: false, cache: false)
|
711
|
+
entity_reference = entity_id.blank? ? 'Default' : entity_id
|
712
|
+
|
713
|
+
if object_id.present? && ![Array, String].include?(object_id.class)
|
714
|
+
raise "Object Id can only be a string or an array of strings"
|
715
|
+
end
|
716
|
+
|
717
|
+
if defined?(Redis.current) && object_id.present? && object_id.class == String && object_id.present?
|
718
|
+
stub_catalog = cache ? decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}")) : nil
|
719
|
+
object_hierarchy = decrypt_data(data: Redis.current.get("Catalog:#{self.id}:#{object_id}:Hierarchy"))
|
720
|
+
end
|
721
|
+
|
722
|
+
if defined?(object_hierarchy)
|
723
|
+
object_hierarchy ||= (JSON.parse(ActiveRecord::Base.connection.execute('SELECT catalog_mapping #> \'{%s}\' AS item FROM "public"."zuora_connect_app_instances" WHERE "id" = %s LIMIT 1' % [entity_reference, self.id]).first["item"] || "{}") [object_id] || {"productId" => "SAFTEY", "productRatePlanId" => "SAFTEY", "productRatePlanChargeId" => "SAFTEY"})
|
724
|
+
end
|
725
|
+
|
726
|
+
case object
|
727
|
+
when :product
|
728
|
+
if object_id.nil?
|
729
|
+
string =
|
730
|
+
"SELECT "\
|
731
|
+
"json_object_agg(product_id, product #{child_objects ? '' : '- \'productRatePlans\''}) AS item "\
|
732
|
+
"FROM "\
|
733
|
+
"\"public\".\"zuora_connect_app_instances\", "\
|
734
|
+
"jsonb_each((\"public\".\"zuora_connect_app_instances\".\"catalog\" #> '{%s}' )) AS e(product_id, product) "\
|
735
|
+
"WHERE "\
|
736
|
+
"\"id\" = %s" % [entity_reference, self.id]
|
737
|
+
else
|
738
|
+
if object_id.class == String
|
739
|
+
string =
|
740
|
+
"SELECT "\
|
741
|
+
"(catalog #> '{%s, %s}') #{child_objects ? '' : '- \'productRatePlans\''} AS item "\
|
742
|
+
"FROM "\
|
743
|
+
"\"public\".\"zuora_connect_app_instances\" "\
|
744
|
+
"WHERE "\
|
745
|
+
"\"id\" = %s" % [entity_reference, object_id.blank? ? BLANK_OBJECT_ID_LOOKUP : object_id, self.id]
|
746
|
+
elsif object_id.class == Array
|
747
|
+
string =
|
748
|
+
"SELECT "\
|
749
|
+
"json_object_agg(product_id, product #{child_objects ? '' : '- \'productRatePlans\''}) AS item "\
|
750
|
+
"FROM "\
|
751
|
+
"\"public\".\"zuora_connect_app_instances\", "\
|
752
|
+
"jsonb_each((\"public\".\"zuora_connect_app_instances\".\"catalog\" #> '{%s}' )) AS e(product_id, product) "\
|
753
|
+
"WHERE "\
|
754
|
+
"\"product_id\" IN (\'%s\') AND "\
|
755
|
+
"\"id\" = %s" % [entity_reference, object_id.join("\',\'"), self.id]
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
when :rateplan
|
760
|
+
if object_id.nil?
|
761
|
+
string =
|
762
|
+
"SELECT "\
|
763
|
+
"json_object_agg(rateplan_id, rateplan #{child_objects ? '' : '- \'productRatePlanCharges\''}) AS item "\
|
764
|
+
"FROM "\
|
765
|
+
"\"public\".\"zuora_connect_app_instances\", "\
|
766
|
+
"jsonb_each((\"public\".\"zuora_connect_app_instances\".\"catalog\" #> '{%s}' )) AS e(product_id, product), "\
|
767
|
+
"jsonb_each(product #> '{productRatePlans}') AS ee(rateplan_id, rateplan) "\
|
768
|
+
"WHERE "\
|
769
|
+
"\"id\" = %s" % [entity_reference, self.id]
|
770
|
+
else
|
771
|
+
if object_id.class == String
|
772
|
+
string =
|
773
|
+
"SELECT "\
|
774
|
+
"(catalog #> '{%s, %s, productRatePlans, %s}') #{child_objects ? '' : '- \'productRatePlanCharges\''} AS item "\
|
775
|
+
"FROM "\
|
776
|
+
"\"public\".\"zuora_connect_app_instances\" "\
|
777
|
+
"WHERE "\
|
778
|
+
"\"id\" = %s" % [entity_reference, object_hierarchy['productId'], object_id.blank? ? BLANK_OBJECT_ID_LOOKUP : object_id, self.id]
|
779
|
+
elsif object_id.class == Array
|
780
|
+
string =
|
781
|
+
"SELECT "\
|
782
|
+
"json_object_agg(rateplan_id, rateplan #{child_objects ? '' : '- \'productRatePlanCharges\''}) AS item "\
|
783
|
+
"FROM "\
|
784
|
+
"\"public\".\"zuora_connect_app_instances\", "\
|
785
|
+
"jsonb_each((\"public\".\"zuora_connect_app_instances\".\"catalog\" #> '{%s}' )) AS e(product_id, product), "\
|
786
|
+
"jsonb_each(product #> '{productRatePlans}') AS ee(rateplan_id, rateplan) "\
|
787
|
+
"WHERE "\
|
788
|
+
"\"rateplan_id\" IN (\'%s\') AND "\
|
789
|
+
"\"id\" = %s" % [entity_reference, object_id.join("\',\'"), self.id]
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
when :charge
|
794
|
+
if object_id.nil?
|
795
|
+
string =
|
796
|
+
"SELECT "\
|
797
|
+
"json_object_agg(charge_id, charge) as item "\
|
798
|
+
"FROM "\
|
799
|
+
"\"public\".\"zuora_connect_app_instances\", "\
|
800
|
+
"jsonb_each((\"public\".\"zuora_connect_app_instances\".\"catalog\" #> '{%s}' )) AS e(product_id, product), "\
|
801
|
+
"jsonb_each(product #> '{productRatePlans}') AS ee(rateplan_id, rateplan), "\
|
802
|
+
"jsonb_each(rateplan #> '{productRatePlanCharges}') AS eee(charge_id, charge) "\
|
803
|
+
"WHERE "\
|
804
|
+
"\"id\" = %s" % [entity_reference, self.id]
|
805
|
+
else
|
806
|
+
if object_id.class == String
|
807
|
+
string =
|
808
|
+
"SELECT "\
|
809
|
+
"catalog #> '{%s, %s, productRatePlans, %s, productRatePlanCharges, %s}' AS item "\
|
810
|
+
"FROM "\
|
811
|
+
"\"public\".\"zuora_connect_app_instances\" "\
|
812
|
+
"WHERE "\
|
813
|
+
"\"id\" = %s" % [entity_reference, object_hierarchy['productId'], object_hierarchy['productRatePlanId'], object_id.blank? ? BLANK_OBJECT_ID_LOOKUP : object_id , self.id]
|
814
|
+
|
815
|
+
elsif object_id.class == Array
|
816
|
+
string =
|
817
|
+
"SELECT "\
|
818
|
+
"json_object_agg(charge_id, charge) AS item "\
|
819
|
+
"FROM "\
|
820
|
+
"\"public\".\"zuora_connect_app_instances\", "\
|
821
|
+
"jsonb_each((\"public\".\"zuora_connect_app_instances\".\"catalog\" #> '{%s}' )) AS e(product_id, product), "\
|
822
|
+
"jsonb_each(product #> '{productRatePlans}') AS ee(rateplan_id, rateplan), "\
|
823
|
+
"jsonb_each(rateplan #> '{productRatePlanCharges}') AS eee(charge_id, charge) "\
|
824
|
+
"WHERE "\
|
825
|
+
"\"charge_id\" IN (\'%s\') AND "\
|
826
|
+
"\"id\" = %s" % [entity_reference, object_id.join("\',\'"), self.id]
|
827
|
+
end
|
828
|
+
end
|
829
|
+
else
|
830
|
+
raise "Available objects include [:product, :rateplan, :charge]"
|
831
|
+
end
|
832
|
+
|
833
|
+
stub_catalog ||= JSON.parse(ActiveRecord::Base.connection.execute(string).first["item"] || "{}")
|
834
|
+
|
835
|
+
if defined?(Redis.current) && object_id.present? && object_id.class == String && object_id.present?
|
836
|
+
if cache
|
837
|
+
Redis.current.sadd("Catalog:#{self.id}:Keys", ["Catalog:#{self.id}:#{object_id}:Hierarchy", "Catalog:#{self.id}:#{object_id}:Children:#{child_objects}"])
|
838
|
+
Redis.current.set("Catalog:#{self.id}:#{object_id}:Hierarchy", encrypt_data(data: object_hierarchy))
|
839
|
+
Redis.current.set("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}", encrypt_data(data: stub_catalog))
|
840
|
+
else
|
841
|
+
Redis.current.sadd("Catalog:#{self.id}:Keys", ["Catalog:#{self.id}:#{object_id}:Hierarchy"])
|
842
|
+
Redis.current.set("Catalog:#{self.id}:#{object_id}:Hierarchy", encrypt_data(data: object_hierarchy))
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
return stub_catalog
|
847
|
+
end
|
848
|
+
### END Catalog Helping Methods #####
|
849
|
+
|
850
|
+
### START S3 Helping Methods #####
|
851
|
+
def s3_client
|
852
|
+
require 'aws-sdk-s3'
|
853
|
+
if ZuoraConnect.configuration.mode == "Development"
|
854
|
+
@s3_client ||= Aws::S3::Resource.new(region: ZuoraConnect.configuration.aws_region,access_key_id: ZuoraConnect.configuration.dev_mode_access_key_id,secret_access_key: ZuoraConnect.configuration.dev_mode_secret_access_key)
|
855
|
+
else
|
856
|
+
@s3_client ||= Aws::S3::Resource.new(region: ZuoraConnect.configuration.aws_region)
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
def upload_to_s3(local_file,s3_path = nil)
|
861
|
+
s3_path = local_file.split("/").last if s3_path.nil?
|
862
|
+
obj = self.s3_client.bucket(ZuoraConnect.configuration.s3_bucket_name).object("#{ZuoraConnect.configuration.s3_folder_name}/#{self.id.to_s}/#{s3_path}}")
|
863
|
+
obj.upload_file(local_file, :server_side_encryption => 'AES256')
|
864
|
+
end
|
865
|
+
|
866
|
+
def get_s3_file_url(key)
|
867
|
+
require 'aws-sdk-s3'
|
868
|
+
signer = Aws::S3::Presigner.new(client: self.s3_client)
|
869
|
+
url = signer.presigned_url(:get_object, bucket: ZuoraConnect.configuration.s3_bucket_name, key: "#{ZuoraConnect.configuration.s3_folder_name}/#{self.id.to_s}/#{key}")
|
870
|
+
end
|
871
|
+
### END S3 Helping Methods #####
|
872
|
+
|
873
|
+
### START Aggregate Grouping Helping Methods ####
|
874
|
+
def self.refresh_aggregate_table(aggregate_name: 'all_tasks_processing', table_name: 'tasks', where_clause: "where status in ('Processing', 'Queued')", index_table: true)
|
875
|
+
self.update_functions
|
876
|
+
if index_table
|
877
|
+
ActiveRecord::Base.connection.execute('SELECT "shared_extensions".refresh_aggregate_table(\'%s\', \'%s\', %s, \'Index\');' % [aggregate_name, table_name, ActiveRecord::Base.connection.quote(where_clause)])
|
878
|
+
else
|
879
|
+
ActiveRecord::Base.connection.execute('SELECT "shared_extensions".refresh_aggregate_table(\'%s\', \'%s\', %s, \'NO\');' % [aggregate_name, table_name, ActiveRecord::Base.connection.quote(where_clause)])
|
880
|
+
end
|
881
|
+
end
|
882
|
+
|
883
|
+
def self.update_functions
|
884
|
+
ActiveRecord::Base.connection.execute(File.read("#{Gem.loaded_specs["zuora_connect"].gem_dir}/app/views/sql/refresh_aggregate_table.txt"))
|
885
|
+
end
|
886
|
+
### END Aggregate Grouping Helping Methods #####
|
887
|
+
|
888
|
+
# Overide this method to avoid the new session call for api requests that use the before filter authenticate_app_api_request.
|
889
|
+
# This can be usefull for apps that dont need connect metadata call, or credentials, to operate for api requests
|
890
|
+
def new_session_for_api_requests(params: {})
|
891
|
+
return true
|
892
|
+
end
|
893
|
+
|
894
|
+
# Overide this method to avoid the new session call for ui requests that use the before filter authenticate_connect_app_request.
|
895
|
+
# This can be usefull for apps that dont need connect metadata call, or credentials, to operate for ui requests
|
896
|
+
def new_session_for_ui_requests(params: {})
|
897
|
+
return true
|
898
|
+
end
|
899
|
+
|
900
|
+
#Method for overiding droping of an app instance
|
901
|
+
def drop_instance
|
902
|
+
self.drop_message = 'Ok to drop'
|
903
|
+
return true
|
904
|
+
end
|
905
|
+
|
906
|
+
def reload_attributes(selected_attributes)
|
907
|
+
raise "Attibutes must be array" if selected_attributes.class != Array
|
908
|
+
value_attributes = self.class.unscoped.where(:id=>id).select(selected_attributes).first.attributes
|
909
|
+
value_attributes.each do |key, value|
|
910
|
+
next if key == "id" && value.blank?
|
911
|
+
self.send(:write_attribute, key, value)
|
912
|
+
end
|
913
|
+
return self
|
914
|
+
end
|
915
|
+
|
916
|
+
def instance_failure(failure)
|
917
|
+
raise failure
|
918
|
+
end
|
919
|
+
|
920
|
+
def send_email
|
921
|
+
end
|
922
|
+
|
923
|
+
def login_lookup(type: "Zuora")
|
924
|
+
results = []
|
925
|
+
self.logins.each do |name, login|
|
926
|
+
results << login if login.tenant_type == type
|
927
|
+
end
|
928
|
+
return results
|
929
|
+
end
|
930
|
+
|
931
|
+
def self.decrypt_response(resp)
|
932
|
+
OpenSSL::PKey::RSA.new(ZuoraConnect.configuration.private_key).private_decrypt(resp)
|
933
|
+
end
|
934
|
+
|
935
|
+
def attr_builder(field,val)
|
936
|
+
singleton_class.class_eval { attr_accessor "#{field}" }
|
937
|
+
send("#{field}=", val)
|
938
|
+
end
|
939
|
+
|
940
|
+
def method_missing(method_sym, *arguments, &block)
|
941
|
+
if method_sym.to_s.include?("login")
|
942
|
+
Rails.logger.fatal("Method Missing #{method_sym}")
|
943
|
+
Rails.logger.fatal("Instance Data: #{self.task_data}")
|
944
|
+
Rails.logger.fatal("Instance Logins: #{self.logins}")
|
945
|
+
end
|
946
|
+
super
|
947
|
+
end
|
948
|
+
|
949
|
+
method_hook :refresh, :updateOption, :update_logins, :before => :check_oauth_state
|
950
|
+
method_hook :new_session, :refresh, :build_task, :after => :apartment_switch
|
951
|
+
end
|
952
|
+
end
|