zuora_connect-D 1.6.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +38 -0
  4. data/app/assets/javascripts/zuora_connect/api/v1/app_instance.js +2 -0
  5. data/app/assets/javascripts/zuora_connect/application.js +13 -0
  6. data/app/assets/stylesheets/zuora_connect/api/v1/app_instance.css +4 -0
  7. data/app/assets/stylesheets/zuora_connect/application.css +15 -0
  8. data/app/controllers/zuora_connect/admin/tenant_controller.rb +11 -0
  9. data/app/controllers/zuora_connect/api/v1/app_instance_controller.rb +37 -0
  10. data/app/controllers/zuora_connect/application_controller.rb +8 -0
  11. data/app/controllers/zuora_connect/static_controller.rb +26 -0
  12. data/app/helpers/zuora_connect/api/v1/app_instance_helper.rb +4 -0
  13. data/app/helpers/zuora_connect/application_helper.rb +5 -0
  14. data/app/models/zuora_connect/app_instance.rb +5 -0
  15. data/app/models/zuora_connect/app_instance_base.rb +755 -0
  16. data/app/models/zuora_connect/login.rb +37 -0
  17. data/app/views/layouts/zuora_connect/application.html.erb +14 -0
  18. data/app/views/sql/refresh_aggregate_table.txt +84 -0
  19. data/app/views/zuora_connect/static/invalid_app_instance_error.html.erb +65 -0
  20. data/app/views/zuora_connect/static/session_error.html.erb +63 -0
  21. data/config/initializers/apartment.rb +95 -0
  22. data/config/initializers/object_method_hooks.rb +27 -0
  23. data/config/initializers/redis.rb +10 -0
  24. data/config/initializers/resque.rb +5 -0
  25. data/config/initializers/to_bool.rb +24 -0
  26. data/config/routes.rb +12 -0
  27. data/db/migrate/20100718151733_create_connect_app_instances.rb +9 -0
  28. data/db/migrate/20101024162319_add_tokens_to_app_instance.rb +6 -0
  29. data/db/migrate/20101024220705_add_token_to_app_instance.rb +5 -0
  30. data/db/migrate/20110131211919_add_sessions_table.rb +13 -0
  31. data/db/migrate/20110411200303_add_expiration_to_app_instance.rb +5 -0
  32. data/db/migrate/20110413191512_add_new_api_token.rb +5 -0
  33. data/db/migrate/20110503003602_add_catalog_data_to_app_instance.rb +6 -0
  34. data/db/migrate/20110503003603_add_catalog_mappings_to_app_instance.rb +5 -0
  35. data/db/migrate/20110503003604_catalog_default.rb +5 -0
  36. data/db/migrate/20180301052853_add_catalog_attempted_at.rb +5 -0
  37. data/lib/resque/additions.rb +53 -0
  38. data/lib/resque/dynamic_queues.rb +142 -0
  39. data/lib/resque/self_lookup.rb +19 -0
  40. data/lib/tasks/zuora_connect_tasks.rake +24 -0
  41. data/lib/zuora_connect.rb +38 -0
  42. data/lib/zuora_connect/configuration.rb +40 -0
  43. data/lib/zuora_connect/controllers/helpers.rb +165 -0
  44. data/lib/zuora_connect/engine.rb +30 -0
  45. data/lib/zuora_connect/exceptions.rb +67 -0
  46. data/lib/zuora_connect/railtie.rb +35 -0
  47. data/lib/zuora_connect/version.rb +3 -0
  48. data/lib/zuora_connect/views/helpers.rb +9 -0
  49. data/test/controllers/zuora_connect/api/v1/app_instance_controller_test.rb +13 -0
  50. data/test/dummy/README.rdoc +28 -0
  51. data/test/dummy/Rakefile +6 -0
  52. data/test/dummy/app/assets/javascripts/application.js +13 -0
  53. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  54. data/test/dummy/app/controllers/application_controller.rb +5 -0
  55. data/test/dummy/app/helpers/application_helper.rb +2 -0
  56. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  57. data/test/dummy/bin/bundle +3 -0
  58. data/test/dummy/bin/rails +4 -0
  59. data/test/dummy/bin/rake +4 -0
  60. data/test/dummy/bin/setup +29 -0
  61. data/test/dummy/config.ru +4 -0
  62. data/test/dummy/config/application.rb +26 -0
  63. data/test/dummy/config/boot.rb +5 -0
  64. data/test/dummy/config/database.yml +25 -0
  65. data/test/dummy/config/environment.rb +5 -0
  66. data/test/dummy/config/environments/development.rb +41 -0
  67. data/test/dummy/config/environments/production.rb +79 -0
  68. data/test/dummy/config/environments/test.rb +42 -0
  69. data/test/dummy/config/initializers/assets.rb +11 -0
  70. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  71. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  72. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  73. data/test/dummy/config/initializers/inflections.rb +16 -0
  74. data/test/dummy/config/initializers/mime_types.rb +4 -0
  75. data/test/dummy/config/initializers/session_store.rb +3 -0
  76. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  77. data/test/dummy/config/locales/en.yml +23 -0
  78. data/test/dummy/config/routes.rb +4 -0
  79. data/test/dummy/config/secrets.yml +22 -0
  80. data/test/dummy/db/development.sqlite3 +0 -0
  81. data/test/dummy/db/test.sqlite3 +0 -0
  82. data/test/dummy/log/development.log +2 -0
  83. data/test/dummy/log/test.log +0 -0
  84. data/test/dummy/public/404.html +67 -0
  85. data/test/dummy/public/422.html +67 -0
  86. data/test/dummy/public/500.html +66 -0
  87. data/test/dummy/public/favicon.ico +0 -0
  88. data/test/fixtures/zuora_connect/app_instances.yml +11 -0
  89. data/test/integration/navigation_test.rb +8 -0
  90. data/test/lib/generators/zuora_connect/datatable_generator_test.rb +16 -0
  91. data/test/models/zuora_connect/app_instance_test.rb +9 -0
  92. data/test/test_helper.rb +21 -0
  93. data/test/zuora_connect_test.rb +7 -0
  94. metadata +408 -0
@@ -0,0 +1,9 @@
1
+ class CreateConnectAppInstances < ActiveRecord::Migration
2
+ def change
3
+ if !ActiveRecord::Base.connection.table_exists?('zuora_connect_app_instances')
4
+ create_table :zuora_connect_app_instances do |t|
5
+ t.timestamps null: false
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ class AddTokensToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :access_token, :string unless column_exists? :zuora_connect_app_instances, :access_token
4
+ add_column :zuora_connect_app_instances, :refresh_token, :string unless column_exists? :zuora_connect_app_instances, :refresh_token
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddTokenToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :token, :string unless column_exists? :zuora_connect_app_instances, :token
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ class AddSessionsTable < ActiveRecord::Migration
2
+ def change
3
+ if !ActiveRecord::Base.connection.table_exists?('sessions')
4
+ create_table :sessions do |t|
5
+ t.string :session_id, :null => false
6
+ t.text :data
7
+ t.timestamps
8
+ end
9
+ add_index :sessions, :session_id, :unique => true
10
+ add_index :sessions, :updated_at
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class AddExpirationToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :oauth_expires_at, :datetime unless column_exists? :zuora_connect_app_instances, :oauth_expires_at
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddNewApiToken < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :api_token, :string unless column_exists? :zuora_connect_app_instances, :api_token
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class AddCatalogDataToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :catalog_updated_at, :datetime unless column_exists? :zuora_connect_app_instances, :catalog_updated_at
4
+ add_column :zuora_connect_app_instances, :catalog, :jsonb, default: {} unless column_exists? :zuora_connect_app_instances, :catalog
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddCatalogMappingsToAppInstance < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :catalog_mapping, :jsonb, default: {} unless column_exists? :zuora_connect_app_instances, :catalog_mapping
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class CatalogDefault < ActiveRecord::Migration
2
+ def change
3
+ change_column :zuora_connect_app_instances, :catalog, :jsonb, default: {}
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddCatalogAttemptedAt < ActiveRecord::Migration
2
+ def change
3
+ add_column :zuora_connect_app_instances, :catalog_update_attempt_at, :datetime unless column_exists? :zuora_connect_app_instances, :catalog_update_attempt_at
4
+ end
5
+ end
@@ -0,0 +1,53 @@
1
+ module Resque
2
+ module Additions
3
+ def dequeue_from(queue, klass, *args)
4
+ ####### ------ Resque Job --------
5
+ # Perform before_dequeue hooks. Don't perform dequeue if any hook returns false
6
+ before_hooks = Plugin.before_dequeue_hooks(klass).collect do |hook|
7
+ klass.send(hook, *args)
8
+ end
9
+ return if before_hooks.any? { |result| result == false }
10
+
11
+ destroyed = Job.destroy(queue, klass, *args)
12
+
13
+ Plugin.after_dequeue_hooks(klass).each do |hook|
14
+ klass.send(hook, *args)
15
+ end
16
+
17
+ destroyed
18
+ end
19
+
20
+ ####### ------ Resque Delayed Job --------
21
+ # Returns delayed jobs schedule timestamp for +klass+, +args+.
22
+ def scheduled_at_with_queue(queue, klass, *args)
23
+ search = encode(job_to_hash_with_queue(queue,klass, args))
24
+ redis.smembers("timestamps:#{search}").map do |key|
25
+ key.tr('delayed:', '').to_i
26
+ end
27
+ end
28
+
29
+ # Given an encoded item, remove it from the delayed_queue
30
+ def remove_delayed_with_queue(queue, klass, *args)
31
+ search = encode(job_to_hash_with_queue(queue,klass, args))
32
+ remove_delayed_job(search)
33
+ end
34
+
35
+ #Given a timestamp and job (klass + args) it removes all instances and
36
+ # returns the count of jobs removed.
37
+ #
38
+ # O(N) where N is the number of jobs scheduled to fire at the given
39
+ # timestamp
40
+ def remove_delayed_job_with_queue_from_timestamp(timestamp, queue, klass, *args)
41
+ return 0 if Resque.inline?
42
+
43
+ key = "delayed:#{timestamp.to_i}"
44
+ encoded_job = encode(job_to_hash_with_queue(queue, klass, args))
45
+
46
+ redis.srem("timestamps:#{encoded_job}", key)
47
+ count = redis.lrem(key, 0, encoded_job)
48
+ clean_up_timestamp(key, timestamp)
49
+
50
+ count
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,142 @@
1
+ module Resque
2
+ module DynamicQueues
3
+ def filter_busy_queues qs
4
+ busy_queues = Resque::Worker.working.map { |worker| worker.job["queue"] }.compact
5
+ Array(qs.dup).compact - busy_queues
6
+ end
7
+
8
+ def rotated_queues
9
+ @n ||= 0
10
+ @n += 1
11
+ rot_queues = queues # since we rely on the resque-dynamic-queues plugin, this is all the queues, expanded out
12
+ if rot_queues.size > 0
13
+ @n = @n % rot_queues.size
14
+ rot_queues.rotate(@n)
15
+ else
16
+ rot_queues
17
+ end
18
+ end
19
+
20
+ def queue_depth queuename
21
+ busy_queues = Resque::Worker.working.map { |worker| worker.job["queue"] }.compact
22
+ # find the queuename, count it.
23
+ busy_queues.select {|q| q == queuename }.size
24
+ end
25
+
26
+ DEFAULT_QUEUE_DEPTH = 0
27
+ def should_work_on_queue? queuename
28
+ return true if @queues.include? '*' # workers with QUEUES=* are special and are not subject to queue depth setting
29
+ max = DEFAULT_QUEUE_DEPTH
30
+ unless ENV["RESQUE_QUEUE_DEPTH"].nil? || ENV["RESQUE_QUEUE_DEPTH"] == ""
31
+ max = ENV["RESQUE_QUEUE_DEPTH"].to_i
32
+ end
33
+ return true if max == 0 # 0 means no limiting
34
+ cur_depth = queue_depth(queuename)
35
+ log! "queue #{queuename} depth = #{cur_depth} max = #{max}"
36
+ return true if cur_depth < max
37
+ false
38
+ end
39
+
40
+ def reserve_with_round_robin
41
+ grouped_queues = queues.sort.group_by{|u| /(\d{1,20})_.*/.match(u) ? /(\d{1,20})_.*/.match(u).captures.first : nil}
42
+
43
+ #Instance queue grouping
44
+ if !grouped_queues.keys.include?(nil) && grouped_queues.keys.size > 0
45
+ @n ||= 0
46
+ @n += 1
47
+ @n = @n % grouped_queues.keys.size
48
+
49
+ grouped_queues.keys.rotate(@n).each do |key|
50
+ grouped_queues[key].each do |queue|
51
+ log! "Checking #{queue}"
52
+ if should_work_on_queue?(queue) && @job_in_progress = Resque::Job.reserve(queue)
53
+ log! "Found job on #{queue}"
54
+ return @job_in_progress
55
+ end
56
+ end
57
+ @n += 1 # Start the next search at the queue after the one from which we pick a job.
58
+ end
59
+ nil
60
+ else
61
+ return reserve_without_round_robin
62
+ end
63
+
64
+ rescue Exception => e
65
+ log "Error reserving job: #{e.inspect}"
66
+ log e.backtrace.join("\n")
67
+ raise e
68
+ end
69
+
70
+ # Returns a list of queues to use when searching for a job.
71
+ #
72
+ # A splat ("*") means you want every queue (in alpha order) - this
73
+ # can be useful for dynamically adding new queues.
74
+ #
75
+ # The splat can also be used as a wildcard within a queue name,
76
+ # e.g. "*high*", and negation can be indicated with a prefix of "!"
77
+ #
78
+ # An @key can be used to dynamically look up the queue list for key from redis.
79
+ # If no key is supplied, it defaults to the worker's hostname, and wildcards
80
+ # and negations can be used inside this dynamic queue list. Set the queue
81
+ # list for a key with Resque.set_dynamic_queue(key, ["q1", "q2"]
82
+ #
83
+ def queues_with_dynamic
84
+ queue_names = @queues.dup
85
+
86
+ return queues_without_dynamic if queue_names.grep(/(^!)|(^@)|(\*)/).size == 0
87
+
88
+ real_queues = Resque.queues
89
+ matched_queues = []
90
+
91
+ #Remove Queues under Api Limits
92
+ api_limit_instances = Redis.current.keys('APILimits:*').map {|key| key.split('APILimits:').last.to_i}
93
+ real_queues = real_queues.select {|key| key if !api_limit_instances.include?((key.match(/^(\d*)_.*/) || [])[1].to_i)} ## 2
94
+
95
+ #Queue Pausing
96
+ paused_instances = Redis.current.keys('resque:PauseQueue:*').map {|key| key.split('resque:PauseQueue:').last.to_i}
97
+ real_queues = real_queues.select {|key| key if !paused_instances.include?((key.match(/^(\d*)_.*/) || [])[1].to_i)}
98
+
99
+ while q = queue_names.shift
100
+ q = q.to_s
101
+
102
+ if q =~ /^(!)?@(.*)/
103
+ key = $2.strip
104
+ key = hostname if key.size == 0
105
+
106
+ add_queues = Resque.get_dynamic_queue(key)
107
+ add_queues.map! { |q| q.gsub!(/^!/, '') || q.gsub!(/^/, '!') } if $1
108
+
109
+ queue_names.concat(add_queues)
110
+ next
111
+ end
112
+
113
+ if q =~ /^!/
114
+ negated = true
115
+ q = q[1..-1]
116
+ end
117
+
118
+ patstr = q.gsub(/\*/, '.*')
119
+ pattern = /^#{patstr}$/
120
+ if negated
121
+ matched_queues -= matched_queues.grep(pattern)
122
+ else
123
+ matches = real_queues.grep(/^#{pattern}$/)
124
+ matches = [q] if matches.size == 0 && q == patstr
125
+ matched_queues.concat(matches.sort)
126
+ end
127
+ end
128
+
129
+ return matched_queues.uniq
130
+ end
131
+
132
+
133
+ def self.included(receiver)
134
+ receiver.class_eval do
135
+ alias queues_without_dynamic queues
136
+ alias queues queues_with_dynamic
137
+ alias reserve_without_round_robin reserve
138
+ alias reserve reserve_with_round_robin
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,19 @@
1
+ module Resque
2
+ module SelfLookup
3
+ def payload_class_enhanced
4
+ @payload_class ||= constantize(@payload['class'])
5
+ @payload_class.instance_eval { class << self; self end }.send(:attr_accessor, :worker)
6
+ @payload_class.instance_eval { class << self; self end }.send(:attr_accessor, :job)
7
+ @payload_class.worker = self.worker
8
+ @payload_class.job = self
9
+ return @payload_class
10
+ end
11
+
12
+ def self.included(receiver)
13
+ receiver.class_eval do
14
+ alias payload_class_old payload_class
15
+ alias payload_class payload_class_enhanced
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ # desc "Explaining what the task does"
2
+ # task :connect do
3
+ # # Task goes here
4
+ # end
5
+
6
+ namespace :db do
7
+ desc 'Also create shared_extensions Schema'
8
+ task :extensions => :environment do
9
+ # Create Schema
10
+ ActiveRecord::Base.connection.execute 'CREATE SCHEMA IF NOT EXISTS shared_extensions;'
11
+ # Enable Hstore
12
+ ActiveRecord::Base.connection.execute 'CREATE EXTENSION IF NOT EXISTS HSTORE SCHEMA shared_extensions;'
13
+ # Enable UUID-OSSP
14
+ ActiveRecord::Base.connection.execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp" SCHEMA shared_extensions;'
15
+ end
16
+ end
17
+
18
+ Rake::Task["db:create"].enhance do
19
+ Rake::Task["db:extensions"].invoke
20
+ end
21
+
22
+ Rake::Task["db:test:purge"].enhance do
23
+ Rake::Task["db:extensions"].invoke
24
+ end
@@ -0,0 +1,38 @@
1
+ require 'zuora_connect/configuration'
2
+ require "zuora_connect/engine"
3
+ require 'zuora_connect/exceptions'
4
+ require 'zuora_connect/controllers/helpers'
5
+ require 'zuora_connect/views/helpers'
6
+ require 'zuora_connect/railtie'
7
+ require 'resque/additions'
8
+ require 'resque/dynamic_queues'
9
+ require 'resque/self_lookup'
10
+
11
+ module ZuoraConnect
12
+ class << self
13
+ attr_accessor :configuration
14
+ end
15
+ module Controllers
16
+ autoload :Helpers, 'zuora_connect/controllers/helpers'
17
+ end
18
+
19
+ module Views
20
+ ActionView::Base.send(:include, Helpers)
21
+ end
22
+
23
+ def self.configuration
24
+ @configuration ||= Configuration.new
25
+ end
26
+
27
+ def self.reset
28
+ @configuration = Configuration.new
29
+ end
30
+
31
+ def self.configure
32
+ yield(configuration)
33
+ ::Apartment.excluded_models << "Delayed::Job" if configuration.delayed_job
34
+ ::Apartment.excluded_models.concat(configuration.additional_apartment_models) if configuration.additional_apartment_models.class == Array
35
+
36
+ return configuration
37
+ end
38
+ end
@@ -0,0 +1,40 @@
1
+ module ZuoraConnect
2
+ class Configuration
3
+ attr_accessor :oauth_client_id, :oauth_client_secret, :oauth_client_redirect_uri,:use_s3, :default_locale,:dev_mode_appinstance ,:dev_mode_admin, :dev_mode_user, :dev_mode_pass, :default_time_zone,:delayed_job,:url, :private_key, :dev_mode_logins,:dev_mode_mode, :dev_mode_options, :mode, :timeout,:dev_mode_secret_access_key,:dev_mode_access_key_id,:aws_region, :s3_bucket_name, :s3_folder_name, :additional_apartment_models
4
+
5
+ def initialize
6
+ @default_locale = :en
7
+ @default_time_zone = Time.zone
8
+ @url = "https://connect.zuora.com"
9
+ @mode = "Production"
10
+ @delayed_job = false
11
+ @use_s3 = false
12
+ @private_key = ENV["CONNECT_KEY"]
13
+ @additional_apartment_models = []
14
+
15
+ # OAuth Settings
16
+ @oauth_client_id = ""
17
+ @oauth_client_secret = ""
18
+ @oauth_client_redirect_uri = "https://connect.zuora.com/"
19
+
20
+ # DEV MODE OPTIONS
21
+ @dev_mode_logins = { "target_login" => {"tenant_type" => "Zuora", "username" => "user", "password" => "pass", "url" => "url"} }
22
+ @dev_mode_options = {"name" => {"config_name" => "name", "datatype" => "type", "value" => "value"}}
23
+ @dev_mode_mode = "Universal"
24
+ @dev_mode_appinstance = "1"
25
+ @dev_mode_user = "test"
26
+ @dev_mode_pass = "test"
27
+ @dev_mode_admin = false
28
+ @dev_mode_secret_access_key = nil
29
+ @dev_mode_access_key_id = nil
30
+ @aws_region = "us-west-2"
31
+ @s3_bucket_name = "rbm-apps"
32
+ @s3_folder_name = Rails.application.class.parent_name
33
+ end
34
+
35
+ def private_key
36
+ raise "Private Key Not Set" if @private_key.blank?
37
+ @private_key.include?("BEGIN") ? @private_key : Base64.urlsafe_decode64(@private_key)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,165 @@
1
+ require 'apartment/migrator'
2
+ module ZuoraConnect
3
+ module Controllers
4
+ module Helpers
5
+ extend ActiveSupport::Concern
6
+
7
+ def authenticate_app_api_request
8
+ #Skip session for api requests
9
+ Thread.current[:appinstance] = nil
10
+ request.session_options[:skip] = true
11
+ start_time = Time.now
12
+ if request.headers["API-Token"].present?
13
+ @appinstance = ZuoraConnect::AppInstance.where(:api_token => request.headers["API-Token"]).first
14
+ Rails.logger.debug("[#{@appinstance.id}] API REQUEST - API token") if @appinstance.present?
15
+ check_instance
16
+ else
17
+ authenticate_or_request_with_http_basic do |username, password|
18
+ @appinstance = ZuoraConnect::AppInstance.where(:token => password).first
19
+ @appinstance ||= ZuoraConnect::AppInstance.where(:api_token => password).first
20
+ Rails.logger.debug("[#{@appinstance.id}] API REQUEST - Basic Auth") if @appinstance.present?
21
+ check_instance
22
+ end
23
+ end
24
+ Rails.logger.info("[#{@appinstance.blank? ? "N/A" : @appinstance.id}] Authenticate App API Request Completed In - #{(Time.now - start_time).round(2)}s")
25
+ end
26
+
27
+ def authenticate_connect_app_request
28
+ Thread.current[:appinstance] = nil
29
+ start_time = Time.now
30
+ if ZuoraConnect.configuration.mode == "Production"
31
+ if request["data"]
32
+ setup_instance_via_data
33
+ else
34
+ setup_instance_via_session
35
+ end
36
+ else
37
+ setup_instance_via_dev_mode
38
+ end
39
+ #Call .data_lookup with the current session to retrieve session. In some cases session may be stored/cache in redis
40
+ #so data lookup provides a model method that can be overriden per app.
41
+ if params[:controller] != 'zuora_connect/api/v1/app_instance' && params[:action] != 'drop'
42
+ if @appinstance.new_session_for_ui_requests(:params => params)
43
+ @appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
44
+ end
45
+ end
46
+ PaperTrail.whodunnit = session["#{@appinstance.id}::user::email"] if defined?(PaperTrail) && session["#{@appinstance.id}::user::email"].present?
47
+ begin
48
+ I18n.locale = session["#{@appinstance.id}::user::locale"] ? session["#{@appinstance.id}::user::locale"] : @appinstance.locale
49
+ rescue I18n::InvalidLocale => ex
50
+ Rails.logger.error("Invalid Locale: #{ex.message}")
51
+ end
52
+ Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
53
+ Rails.logger.info("[#{@appinstance.blank? ? "N/A" : @appinstance.id}] Authenticate App Request Completed In - #{(Time.now - start_time).round(2)}s")
54
+ end
55
+
56
+ def persist_connect_app_session
57
+ if @appinstance.present?
58
+ if defined?(Redis.current)
59
+ @appinstance.cache_app_instance
60
+ else
61
+ session.merge!(@appinstance.save_data)
62
+ end
63
+ end
64
+ end
65
+
66
+ def check_connect_admin!
67
+ raise ZuoraConnect::Exceptions::AccessDenied.new("User is not an authorized admin for this application") if !session["#{@appinstance.id}::admin"]
68
+ end
69
+
70
+ def check_connect_admin
71
+ return session["#{@appinstance.id}::admin"]
72
+ end
73
+
74
+ private
75
+ def setup_instance_via_data
76
+ session.clear
77
+ values = JSON.parse(ZuoraConnect::AppInstance.decrypt_response(Base64.urlsafe_decode64(request["data"])))
78
+ Rails.logger.debug("Data: #{values.to_json}")
79
+ if values["param_data"]
80
+ values["param_data"].each do |k ,v|
81
+ params[k] = v
82
+ end
83
+ end
84
+ session["#{values["appInstance"]}::destroy"] = values["destroy"]
85
+ session["appInstance"] = values["appInstance"]
86
+ if values["current_user"]
87
+ session["#{values["appInstance"]}::admin"] = values["current_user"]["admin"] ? values["current_user"]["admin"] : false
88
+ session["#{values["appInstance"]}::user::timezone"] = values["current_user"]["timezone"]
89
+ session["#{values["appInstance"]}::user::locale"] = values["current_user"]["locale"]
90
+ session["#{values["appInstance"]}::user::email"] = values["current_user"]["email"]
91
+ end
92
+
93
+ Rails.logger.debug("App Params: #{values.to_json}}") if Rails.env != "production"
94
+
95
+ @appinstance = ZuoraConnect::AppInstance.where(:id => values["appInstance"].to_i).first
96
+ if @appinstance.blank?
97
+ Apartment::Tenant.switch!("public")
98
+ begin
99
+ Apartment::Tenant.create(values["appInstance"].to_s)
100
+ rescue Apartment::TenantExists => ex
101
+ Rails.logger.debug("Tenant Already Exists")
102
+ end
103
+ @appinstance = ZuoraConnect::AppInstance.new(:api_token => values[:api_token],:id => values["appInstance"].to_i, :access_token => values["access_token"].blank? ? values["user"] : values["access_token"], :token => values["refresh_token"] , :refresh_token => values["refresh_token"].blank? ? values["key"] : values["refresh_token"], :oauth_expires_at => values["expires"])
104
+ @appinstance.save(:validate => false)
105
+ else
106
+ @appinstance.access_token = values["access_token"] if !values["access_token"].blank? && @appinstance.access_token != values["access_token"]
107
+ @appinstance.refresh_token = values["refresh_token"] if !values["refresh_token"].blank? && @appinstance.refresh_token != values["refresh_token"]
108
+ @appinstance.oauth_expires_at = values["expires"] if !values["expires"].blank?
109
+ @appinstance.api_token = values["api_token"] if !values["api_token"].blank? && @appinstance.api_token != values["api_token"]
110
+ if @appinstance.access_token_changed? && @appinstance.refresh_token_changed?
111
+ @appinstance.save(:validate => false)
112
+ else
113
+ raise ZuoraConnect::Exceptions::AccessDenied.new("Authorization mistmatch. Possible tampering")
114
+ end
115
+ end
116
+ end
117
+
118
+ def setup_instance_via_session
119
+ if session["appInstance"].present?
120
+ @appinstance = ZuoraConnect::AppInstance.where(:id => session["appInstance"]).first
121
+ else
122
+ raise ZuoraConnect::Exceptions::SessionInvalid.new("Session Blank -- Relaunch Application")
123
+ end
124
+ end
125
+
126
+ def setup_instance_via_dev_mode
127
+ session["appInstance"] = ZuoraConnect.configuration.dev_mode_appinstance
128
+ user = ZuoraConnect.configuration.dev_mode_user
129
+ key = ZuoraConnect.configuration.dev_mode_pass
130
+ values = {:user => user , :key => key, :appinstance => session["appInstance"]}
131
+ @appinstance = ZuoraConnect::AppInstance.where(:id => values[:appinstance].to_i).first
132
+ if @appinstance.blank?
133
+ Apartment::Tenant.switch!("public")
134
+ begin
135
+ Apartment::Tenant.create(values[:appinstance].to_s)
136
+ rescue Apartment::TenantExists => ex
137
+ Apartment::Tenant.drop(values[:appinstance].to_s)
138
+ retry
139
+ end
140
+
141
+ @appinstance = ZuoraConnect::AppInstance.new(:id => values[:appinstance].to_i, :access_token => values[:user], :refresh_token => values[:key], :token => "#{values[:key]}#{values[:key]}", :api_token => "#{values[:key]}#{values[:key]}")
142
+ @appinstance.save(:validate => false)
143
+ end
144
+ if @appinstance.access_token.blank? || @appinstance.refresh_token.blank? || @appinstance.token.blank? || @appinstance.api_token.blank?
145
+ @appinstance.update_attributes!(:access_token => values["user"], :refresh_token => values["key"], :token => "#{values[:key]}#{values[:key]}", :api_token => "#{values[:key]}#{values[:key]}")
146
+ end
147
+ session["#{@appinstance.id}::admin"] = ZuoraConnect.configuration.dev_mode_admin
148
+ end
149
+
150
+ #API ONLY
151
+ def check_instance
152
+ if @appinstance.present?
153
+ if @appinstance.new_session_for_api_requests(:params => params)
154
+ @appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
155
+ end
156
+ Thread.current[:appinstance] = @appinstance
157
+ PaperTrail.whodunnit = "API User" if defined?(PaperTrail)
158
+ return true
159
+ else
160
+ render text: "Access Denied", status: :unauthorized
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end