app_manager 1.2.6 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +7 -1
- data/Gemfile.lock +2 -6
- data/app/controllers/app_manager/charges_controller.rb +157 -157
- data/app/controllers/app_manager/plans_controller.rb +208 -205
- data/app/model/app_manager/app.rb +5 -0
- data/app/model/app_manager/app_manager_record.rb +7 -0
- data/app/model/app_manager/app_structure.rb +5 -0
- data/app/model/app_manager/charge.rb +6 -0
- data/app/model/app_manager/discount_plan.rb +5 -0
- data/app/model/app_manager/extend_trial.rb +5 -0
- data/app/model/app_manager/plan.rb +6 -0
- data/app/model/app_manager/plan_user.rb +5 -0
- data/app_manager.gemspec +1 -1
- data/lib/app_manager/client/connection.rb +5 -7
- data/lib/app_manager/client/plans.rb +34 -34
- data/lib/app_manager/client.rb +21 -23
- data/lib/app_manager/fail_safe.rb +460 -528
- data/lib/app_manager/graphql_helper.rb +1 -1
- data/lib/app_manager/model.rb +188 -200
- data/lib/app_manager/tasks/sync/local_app_manager.rake +2 -3
- data/lib/app_manager/version.rb +1 -1
- data/lib/app_manager.rb +3 -3
- data/lib/generators/app_manager/install/install_generator.rb +40 -31
- data/lib/generators/app_manager/install/templates/failsafe_tables.erb +90 -0
- metadata +11 -16
@@ -33,7 +33,7 @@ module AppManager
|
|
33
33
|
response = ActiveSupport::JSON.decode(response.read_body) rescue nil
|
34
34
|
return response
|
35
35
|
else
|
36
|
-
|
36
|
+
Rollbar.error("=== params missing from any of these api_key, api_version, shopify_domain, shopify_token ===")
|
37
37
|
return []
|
38
38
|
end
|
39
39
|
end
|
data/lib/app_manager/model.rb
CHANGED
@@ -2,270 +2,258 @@ module AppManager
|
|
2
2
|
module Model
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
@@remaining_cache_key = "get_remaining_days_key"
|
6
|
-
@@get_charge_key = "get_charge_key"
|
7
|
-
|
8
5
|
def has_plan_old
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
return active_charge && active_charge['active_charge'].present? && !active_charge['active_charge'].nil? ? true : false
|
6
|
+
if !self[AppManager.configuration.plan_id_or_name_field]
|
7
|
+
return false;
|
8
|
+
end
|
9
|
+
if self[AppManager.configuration.field_names['grandfathered']]
|
10
|
+
return true;
|
11
|
+
end
|
12
|
+
plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
13
|
+
if !plan_id
|
14
|
+
return false;
|
15
|
+
end
|
16
|
+
remaining_days = fetch_static_remaining_days
|
17
|
+
if remaining_days.to_i > 0
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
# plan_obj = AppManager::Client.new
|
21
|
+
# shop_domain = self[AppManager.configuration.shopify_domain_field]
|
22
|
+
# active_charge = plan_obj.get_charge(shop_domain) rescue nil
|
23
|
+
active_charge = fetch_static_get_charge
|
24
|
+
return active_charge && active_charge['active_charge'].present? && !active_charge['active_charge'].nil? ? true : false
|
29
25
|
end
|
30
26
|
|
31
27
|
def has_plan
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
return (response && response['has_plan']) || false
|
28
|
+
plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
29
|
+
if !plan_id
|
30
|
+
return false;
|
31
|
+
end
|
32
|
+
grandfathered = self[AppManager.configuration.field_names['grandfathered']]
|
33
|
+
grandfathered = grandfathered ? 1 : 0
|
34
|
+
shop_domain = self[AppManager.configuration.shopify_domain_field] rescue nil
|
35
|
+
trial_activated_at_val = self[AppManager.configuration.field_names['trial_activated_at']] rescue nil
|
36
|
+
plan_obj = AppManager::Client.new
|
37
|
+
response = plan_obj.has_plan(shop_domain, plan_id, trial_activated_at_val, grandfathered)
|
38
|
+
return (response && response['has_plan']) || false
|
44
39
|
end
|
45
40
|
|
46
41
|
|
47
42
|
def plan_features
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
return pf
|
43
|
+
plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
44
|
+
if !plan_id
|
45
|
+
return []
|
46
|
+
end
|
47
|
+
plan_obj = AppManager::Client.new
|
48
|
+
plans = plan_obj.get_plan(plan_id)
|
49
|
+
if plans && plans['features'].blank?
|
50
|
+
return []
|
51
|
+
end
|
52
|
+
features_by_plan = plans['features'].map { |h| h.slice('value', 'feature_id') }
|
53
|
+
all_features = AppManager.configuration.plan_features
|
54
|
+
feature_plan_ids = features_by_plan.map { |c| c['feature_id'] }
|
55
|
+
pf = all_features.select { |x| feature_plan_ids.include?(x['uuid']) }.each { |g| g["value"] = features_by_plan.find { |e| e['feature_id'] == g['uuid'] }['value'] }
|
56
|
+
return pf
|
63
57
|
end
|
64
58
|
|
65
59
|
|
66
|
-
|
67
60
|
def has_feature(slug)
|
68
|
-
|
61
|
+
self.plan_features.any? && self.plan_features.select { |x| x['slug'].to_s == slug }.size > 0 ? true : false
|
69
62
|
end
|
70
63
|
|
71
64
|
|
72
65
|
def get_feature(slug)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
66
|
+
plan_features = self.plan_features
|
67
|
+
features = plan_features.select { |x| x['slug'].to_s == slug }
|
68
|
+
if features.any?
|
69
|
+
feature = features.first
|
70
|
+
return casted_value(feature['value'], feature['value_type'])
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
81
74
|
end
|
82
75
|
|
83
76
|
def get_remaining_days
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
77
|
+
begin
|
78
|
+
shop_domain = self[AppManager.configuration.shopify_domain_field]
|
79
|
+
trial_activated_at_field = AppManager.configuration.field_names['trial_activated_at']
|
80
|
+
trial_activated_at_val = self[trial_activated_at_field]
|
81
|
+
plan_field = AppManager.configuration.field_names['plan_id']
|
82
|
+
plan_id = self[plan_field]
|
83
|
+
plan_obj = AppManager::Client.new
|
84
|
+
res = plan_obj.get_remaining_days(shop_domain, trial_activated_at_val, plan_id)
|
85
|
+
return (res && !res.nil?) ? res : 0
|
86
|
+
rescue Exception => e
|
87
|
+
Rollbar.error("APP MANAGER Get Remaining Days Failed #{e}")
|
88
|
+
end
|
92
89
|
end
|
93
90
|
|
94
91
|
|
95
|
-
def get_plan(plan_id=nil)
|
96
|
-
|
97
|
-
|
98
|
-
|
92
|
+
def get_plan(plan_id = nil)
|
93
|
+
req_plan_id = nil
|
94
|
+
if !plan_id.nil?
|
95
|
+
req_plan_id = plan_id
|
96
|
+
else
|
97
|
+
shop_plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
98
|
+
if shop_plan_id && !shop_plan_id.nil?
|
99
|
+
req_plan_id = shop_plan_id
|
99
100
|
else
|
100
|
-
|
101
|
-
|
102
|
-
req_plan_id = shop_plan_id
|
103
|
-
else
|
104
|
-
Rails.logger.info "Invalid params, must have charge_id,shop && plan"
|
105
|
-
return {}
|
106
|
-
end
|
101
|
+
Rollbar.error("Invalid params, must have charge_id,shop && plan")
|
102
|
+
return {}
|
107
103
|
end
|
108
|
-
|
109
|
-
|
104
|
+
end
|
105
|
+
plan_obj = AppManager::Client.new if req_plan_id
|
106
|
+
return req_plan_id ? plan_obj.get_plan(req_plan_id) : {}
|
110
107
|
end
|
111
108
|
|
112
109
|
def get_charge
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
110
|
+
shop_plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
111
|
+
found_free_plan = false
|
112
|
+
if shop_plan_id && !shop_plan_id.nil?
|
113
|
+
plan_obj = AppManager::Client.new
|
114
|
+
plan = plan_obj.get_plan(shop_plan_id) rescue nil
|
115
|
+
if plan && plan['price'] == 0 && plan['public'] == true
|
116
|
+
found_free_plan = true
|
117
|
+
return nil
|
122
118
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
end
|
119
|
+
end
|
120
|
+
if !found_free_plan
|
121
|
+
begin
|
122
|
+
shop_domain = self[AppManager.configuration.shopify_domain_field]
|
123
|
+
plan_obj = AppManager::Client.new
|
124
|
+
return plan_obj.get_charge(shop_domain)
|
125
|
+
rescue Exception => e
|
126
|
+
return nil
|
132
127
|
end
|
128
|
+
end
|
133
129
|
end
|
134
130
|
|
135
131
|
def get_all_plans
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
end
|
132
|
+
begin
|
133
|
+
shop_domain = self[AppManager.configuration.shopify_domain_field]
|
134
|
+
shop_plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
135
|
+
active_plan_id = shop_plan_id && shop_plan_id.nil? ? nil : shop_plan_id
|
136
|
+
plan_obj = AppManager::Client.new
|
137
|
+
return plan_obj.get_plans(shop_domain, active_plan_id)
|
138
|
+
rescue Exception => e
|
139
|
+
return []
|
140
|
+
end
|
146
141
|
end
|
147
142
|
|
148
143
|
def cancel_charge
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
144
|
+
begin
|
145
|
+
shop_plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
146
|
+
shop_domain = self[AppManager.configuration.shopify_domain_field]
|
147
|
+
if shop_plan_id && shop_domain
|
148
|
+
plan_obj = AppManager::Client.new
|
149
|
+
plan_obj.cancel_charge(shop_domain, shop_plan_id)
|
150
|
+
end
|
151
|
+
rescue Exception => e
|
152
|
+
return "#{e.inspect}"
|
153
|
+
end
|
159
154
|
end
|
160
155
|
|
161
|
-
def set_default_plan(plan_id=nil)
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
end
|
178
|
-
rescue Exception => e
|
179
|
-
return "#{e.inspect}"
|
156
|
+
def set_default_plan(plan_id = nil)
|
157
|
+
begin
|
158
|
+
if plan_id.nil?
|
159
|
+
shop_domain = self[AppManager.configuration.shopify_domain_field]
|
160
|
+
plan_obj = AppManager::Client.new
|
161
|
+
plans = plan_obj.get_plans(shop_domain)
|
162
|
+
free_plans = plans.select { |x| x['price'] == 0 && x['public'] == true }
|
163
|
+
if free_plans.any?
|
164
|
+
self.plan_id = free_plans.first["id"]
|
165
|
+
self.save
|
166
|
+
else
|
167
|
+
raise Error, "Free Plan is not available"
|
168
|
+
end
|
169
|
+
else
|
170
|
+
self.plan_id = plan_id
|
171
|
+
self.save
|
180
172
|
end
|
173
|
+
rescue Exception => e
|
174
|
+
return "#{e.inspect}"
|
175
|
+
end
|
181
176
|
end
|
182
177
|
|
183
178
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
if (feature_slugs & plan_feature_slugs).any? && ((feature_slugs & plan_feature_slugs).sort == feature_slugs.sort)
|
199
|
-
plan_data.push(plan)
|
200
|
-
end
|
201
|
-
end
|
179
|
+
def get_plans_by_features(feature_slugs, params = "false")
|
180
|
+
if feature_slugs.any?
|
181
|
+
shop_plan_id = self[AppManager.configuration.plan_id_or_name_field]
|
182
|
+
plan_data = []
|
183
|
+
shop_domain = self[AppManager.configuration.shopify_domain_field]
|
184
|
+
plan_obj = AppManager::Client.new
|
185
|
+
plans = plan_obj.get_plans(shop_domain)
|
186
|
+
plans = plans.select { |x| x['interval'] == 'EVERY_30_DAYS' && x['public'] == true }
|
187
|
+
plans.each do |plan|
|
188
|
+
next if (params && !params.nil? && params == "exclude_current_plan" && !shop_plan_id.nil? && plan["id"] == shop_plan_id)
|
189
|
+
if plan && (plan['features'] && plan['features'].any?) && (plan['features'].values && plan['features'].values.any?) && (plan['features'].values.collect { |c| c['slug'] } && plan['features'].values.collect { |c| c['slug'] }.any?)
|
190
|
+
plan_feature_slugs = plan['features'].values.collect { |c| c['slug'] }.sort
|
191
|
+
if (feature_slugs & plan_feature_slugs).any? && ((feature_slugs & plan_feature_slugs).sort == feature_slugs.sort)
|
192
|
+
plan_data.push(plan)
|
202
193
|
end
|
203
|
-
|
204
|
-
else
|
205
|
-
return []
|
194
|
+
end
|
206
195
|
end
|
196
|
+
return plan_data
|
197
|
+
else
|
198
|
+
return []
|
199
|
+
end
|
207
200
|
end
|
208
201
|
|
209
202
|
|
210
|
-
|
211
203
|
def fetch_static_remaining_days
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
end
|
216
|
-
remaining_days = self.get_remaining_days
|
217
|
-
Rails.cache.write(@remaining_cache_key, remaining_days, expires_in: AppManager.configuration.expires_in)
|
218
|
-
return remaining_days
|
204
|
+
@remaining_cache_key = "app-manager-cache/#{self.shopify_domain}-remaining_days"
|
205
|
+
if fetch_cached_static_remaining_days(@remaining_cache_key).present?
|
206
|
+
return fetch_cached_static_remaining_days(@remaining_cache_key)
|
219
207
|
end
|
208
|
+
remaining_days = self.get_remaining_days
|
209
|
+
Rails.cache.write(@remaining_cache_key, remaining_days, expires_in: AppManager.configuration.expires_in)
|
210
|
+
return remaining_days
|
211
|
+
end
|
220
212
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
end
|
213
|
+
def fetch_cached_static_remaining_days(cache_key)
|
214
|
+
if Rails.cache.read(cache_key).present?
|
215
|
+
return Rails.cache.read(cache_key)
|
225
216
|
end
|
226
|
-
|
217
|
+
end
|
227
218
|
|
228
219
|
|
229
220
|
def fetch_static_get_charge
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
221
|
+
@get_charge_key = "app-manager-cache/#{self.shopify_domain}-get_charge"
|
222
|
+
if fetch_cached_static_get_charge(@get_charge_key).present?
|
223
|
+
return fetch_cached_static_get_charge(@get_charge_key)
|
224
|
+
end
|
225
|
+
charge = self.get_charge
|
226
|
+
Rails.cache.write(@get_charge_key, charge, expires_in: AppManager.configuration.expires_in)
|
227
|
+
return charge
|
237
228
|
end
|
238
229
|
|
239
230
|
def fetch_cached_static_get_charge(cache_key)
|
240
|
-
|
241
|
-
|
242
|
-
|
231
|
+
if Rails.cache.read(cache_key).present?
|
232
|
+
return Rails.cache.read(cache_key)
|
233
|
+
end
|
243
234
|
end
|
244
235
|
|
245
236
|
|
246
237
|
private
|
247
|
-
|
248
|
-
def casted_value(value,value_type)
|
249
|
-
|
250
|
-
|
238
|
+
|
239
|
+
def casted_value(value, value_type)
|
240
|
+
case value_type
|
241
|
+
when "integer"
|
251
242
|
value.to_i
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
243
|
+
when "boolean"
|
244
|
+
case value
|
245
|
+
when true, 'true', 1, '1'
|
246
|
+
return true
|
247
|
+
when false, 'false', 0, '0'
|
248
|
+
return false
|
249
|
+
end
|
250
|
+
when "string"
|
260
251
|
value.to_s
|
261
|
-
|
252
|
+
else
|
262
253
|
value
|
263
|
-
|
254
|
+
end
|
264
255
|
end
|
265
256
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
257
|
|
270
258
|
end
|
271
|
-
end
|
259
|
+
end
|
@@ -4,9 +4,8 @@ namespace :sync do
|
|
4
4
|
begin
|
5
5
|
@fs = AppManager::FailSafe.new
|
6
6
|
@fs.sync_app_manager
|
7
|
-
|
8
|
-
|
9
|
-
Rails.logger.info "APP MANAGER SYNC TAKS FAILED #{e.inspect}"
|
7
|
+
rescue Exception => e
|
8
|
+
Rollbar.error("APP MANAGER SYNC TAKS FAILED #{e.inspect}")
|
10
9
|
end
|
11
10
|
end
|
12
11
|
end
|
data/lib/app_manager/version.rb
CHANGED
data/lib/app_manager.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "httparty"
|
4
4
|
require "rails"
|
5
|
-
require 'sqlite3'
|
5
|
+
# require 'sqlite3'
|
6
6
|
require "app_manager/version"
|
7
7
|
require "app_manager/engine"
|
8
8
|
require "app_manager/client"
|
@@ -29,8 +29,8 @@ module AppManager
|
|
29
29
|
def self.clear_cache
|
30
30
|
begin
|
31
31
|
Rails.cache.delete_matched('app-manager-cache/*')
|
32
|
-
|
33
|
-
|
32
|
+
rescue Exception => e
|
33
|
+
Rollbar.error("APP MANAGER Error in Clear Cache #{e}")
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -2,42 +2,51 @@ require "rails/generators/base"
|
|
2
2
|
require "rails/generators/active_record"
|
3
3
|
|
4
4
|
module AppManager
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
5
|
+
module Generators
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
def mount_engine
|
11
|
+
route("mount AppManager::Engine, at: '/'")
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_app_manager_initializer
|
15
|
+
template("app_manager.rb", "config/initializers/app_manager.rb")
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_plan_trial_grandfathered_to_shops_migration
|
19
|
+
if self.class.migration_exists?("db/migrate", "add_plan_trial_grandfathered_to_shops")
|
20
|
+
say_status("skipped", "Migration add_plan_trial_grandfathered_to_shops.rb already exists")
|
21
|
+
else
|
22
|
+
migration_template("add_plan_trial_grandfathered_to_shops.erb", "db/migrate/add_plan_trial_grandfathered_to_shops.rb")
|
23
|
+
end
|
24
|
+
end
|
21
25
|
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
def create_fail_safe
|
27
|
+
if self.class.migration_exists?("db/app_manager", "failsafe_tables")
|
28
|
+
say_status("skipped", "Migration add_fail_safe.rb already exists")
|
29
|
+
else
|
30
|
+
migration_template("failsafe_tables.erb", "db/app_manager/add_fail_safe.rb")
|
31
|
+
end
|
32
|
+
end
|
25
33
|
|
26
|
-
private
|
27
34
|
|
28
|
-
|
29
|
-
Rails.version.match(/\d\.\d/)[0]
|
30
|
-
end
|
35
|
+
private
|
31
36
|
|
32
|
-
|
33
|
-
|
37
|
+
def rails_migration_version
|
38
|
+
Rails.version.match(/\d\.\d/)[0]
|
39
|
+
end
|
34
40
|
|
35
|
-
|
36
|
-
|
37
|
-
ActiveRecord::Generators::Base.next_migration_number(dir)
|
38
|
-
end
|
39
|
-
end
|
41
|
+
class << self
|
42
|
+
private :next_migration_number
|
40
43
|
|
44
|
+
# for generating a timestamp when using `create_migration`
|
45
|
+
def next_migration_number(dir)
|
46
|
+
ActiveRecord::Generators::Base.next_migration_number(dir)
|
41
47
|
end
|
48
|
+
end
|
49
|
+
|
42
50
|
end
|
43
|
-
end
|
51
|
+
end
|
52
|
+
end
|