app_manager 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,125 @@
1
+ module AppManager
2
+ class GraphqlHelper
3
+
4
+ def initialize(shopify_domain,shopify_token)
5
+ @api_key = AppManager.configuration.shopify_api_key || nil
6
+ @api_version = AppManager.configuration.shopify_api_version || nil
7
+ @shopify_domain = shopify_domain
8
+ @shopify_token = shopify_token
9
+ end
10
+
11
+ def rest_client
12
+
13
+ end
14
+
15
+ def api_call(query,is_json=false)
16
+ require 'uri'
17
+ require 'net/http'
18
+ if !@api_key.nil? && !@api_version.nil? && !@shopify_domain.nil? && !@shopify_token.nil?
19
+ url = URI("https://#{@api_key}:#{@shopify_token}@#{@shopify_domain}/admin/api/#{@api_version}/graphql.json")
20
+ http = Net::HTTP.new(url.host, url.port)
21
+ http.use_ssl = true
22
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
23
+ request = Net::HTTP::Post.new(url)
24
+ request["X-Shopify-Access-Token"] = @shopify_token
25
+ request.body = query
26
+ request["Accept"] = 'application/json'
27
+ if is_json.present?
28
+ request["Content-Type"] = 'application/json'
29
+ else
30
+ request["Content-Type"] = 'application/graphql'
31
+ end
32
+ response = http.request(request)
33
+ response = ActiveSupport::JSON.decode(response.read_body) rescue nil
34
+ return response
35
+ else
36
+ Rails.logger.info "=== params missing from any of these api_key, api_version, shopify_domain, shopify_token ==="
37
+ return []
38
+ end
39
+ end
40
+
41
+ def run_graph_api(query,variables = '',is_retrieve_all = false,after = '',is_json = true)
42
+ query = query.dup.force_encoding("UTF-8")
43
+ if variables.present?
44
+ query = {"query": "#{query}","variables": variables }
45
+ end
46
+ if is_json
47
+ response = api_call(query.to_json,true)
48
+ else
49
+ response = api_call(query,false)
50
+ end
51
+ return response
52
+ end
53
+
54
+
55
+ def recurring_charge_api_call(plan,return_url,shop)
56
+ plan_test = nil
57
+ shop_plan_field = AppManager.configuration.field_names['shopify_plan'] rescue nil
58
+ if !plan['affiliate'].nil? && plan['affiliate'].any? && !shop_plan_field.nil? && plan['affiliate'].map{|e| e['value']}.include?(shop[shop_plan_field])
59
+ plan_test = true
60
+ end
61
+ trial_days = plan['trial_days'] || 0
62
+
63
+ if shop && shop.shopify_domain && trial_days
64
+ trial_activated_at_field = AppManager.configuration.field_names['trial_activated_at'] rescue nil
65
+ trial_activated_at = shop[trial_activated_at] rescue nil
66
+ plan_field = AppManager.configuration.plan_id_or_name_field rescue nil
67
+ plan_id_field = shop[@plan_field] rescue nil
68
+ remaining_obj = AppManager::Client.new
69
+ remaining = remaining_obj.get_remaining_days(shop.shopify_domain,trial_activated_at,plan_id_field)
70
+ trial_days = !remaining.nil? ? remaining : trial_days
71
+ end
72
+
73
+ discount_type = plan['discount_type'] || "percentage"
74
+ discount_val = discount_type == "percentage" ? (plan['discount'].to_f/ 100) : plan['discount']
75
+ plan_discount = plan['discount'] ? { "durationLimitInIntervals" => (plan['discount_interval'] || nil), "value" => {"#{discount_type}" => discount_val} } : {}
76
+
77
+ price_details = {
78
+ "price": { "amount": plan['price'], "currencyCode": 'USD' },
79
+ "interval": plan['interval']['value']
80
+ }
81
+ price_details << plan_discount if plan_discount.any?
82
+
83
+ query = 'mutation(
84
+ $name: String!,
85
+ $returnUrl: URL!,
86
+ $trialDays: Int,
87
+ $test: Boolean,
88
+ $lineItems: [AppSubscriptionLineItemInput!]!
89
+ ) {
90
+ appSubscriptionCreate(
91
+ name: $name,
92
+ returnUrl: $returnUrl,
93
+ trialDays: $trialDays,
94
+ test: $test,
95
+ lineItems: $lineItems
96
+ ) {
97
+ userErrors {
98
+ field
99
+ message
100
+ }
101
+ confirmationUrl
102
+ appSubscription {
103
+ id
104
+ }
105
+ }
106
+ }'
107
+
108
+ variables = {
109
+ "name": plan['name'],
110
+ "returnUrl": return_url,
111
+ "trialDays": trial_days,
112
+ "test": plan_test,
113
+ "lineItems": [{
114
+ "plan": {
115
+ "appRecurringPricingDetails": price_details
116
+ }
117
+ }]
118
+ }
119
+ data = run_graph_api(query,variables)
120
+ return data
121
+ end
122
+
123
+ end
124
+ end
125
+
@@ -0,0 +1,98 @@
1
+ module AppManager
2
+ module Model
3
+ extend ActiveSupport::Concern
4
+
5
+
6
+
7
+ def has_plan
8
+ if !self[AppManager.configuration.plan_id_or_name_field]
9
+ return false;
10
+ end
11
+ plan_id = self.plan_id
12
+ if !plan_id
13
+ Rails.logger.info "Plan id found nil or not set"
14
+ return false;
15
+ end
16
+ remaining_days = self.get_remaining_days
17
+ if remaining_days > 0
18
+ return true
19
+ end
20
+ shopify_fields = @field_names = AppManager.configuration.field_names
21
+ plan_obj = AppManager::Client.new
22
+ active_charge = plan_obj.get_charge(shopify_fields['name']) rescue nil
23
+ return active_charge ? true : false
24
+ end
25
+
26
+
27
+
28
+ def plan_features
29
+ plan_id = self.plan_id
30
+ if !plan_id
31
+ raise "Plan id not found"
32
+ end
33
+ plan_obj = AppManager::Client.new
34
+ plans = plan_obj.get_plan(plan_id)
35
+ if plans && plans['features'].blank?
36
+ return []
37
+ end
38
+ features_by_plan = plans['features'].map { |h| h.slice('value', 'feature_id') }
39
+ all_features = AppManager.configuration.plan_features
40
+ feature_plan_ids = features_by_plan.map{|c| c['feature_id']}
41
+ 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'] }
42
+ return pf
43
+ end
44
+
45
+
46
+
47
+ def has_feature(slug)
48
+ self.plan_features.select{|x| x['slug'].to_s == slug }.size > 0
49
+ end
50
+
51
+
52
+ def get_feature(slug)
53
+ plan_features = self.plan_features
54
+ features = plan_features.select{|x| x['slug'].to_s == slug }
55
+ if features.any?
56
+ feature = features.first
57
+ return casted_value(feature['value'],feature['value_type'])
58
+ else
59
+ nil
60
+ end
61
+ end
62
+
63
+ def get_remaining_days
64
+ shop_domain = self[AppManager.configuration.shopify_domain_field]
65
+ trial_activated_at_field = AppManager.configuration.field_names['trial_activated_at']
66
+ trial_activated_at_val = self[trial_activated_at_field]
67
+ plan_field = AppManager.configuration.field_names['plan_id']
68
+ plan_id = self[plan_field]
69
+ plan_obj = AppManager::Client.new
70
+ shop_domain ? plan_obj.get_remaining_days(shop_domain,trial_activated_at_val,plan_id) : 0
71
+ end
72
+
73
+ private
74
+
75
+ def casted_value(value,value_type)
76
+ case value_type
77
+ when "integer"
78
+ value.to_i
79
+ when "boolean"
80
+ case value
81
+ when true, 'true', 1, '1'
82
+ return true
83
+ when false, 'false', 0, '0'
84
+ return false
85
+ end
86
+ when "string"
87
+ value.to_s
88
+ else
89
+ value
90
+ end
91
+ end
92
+
93
+
94
+
95
+
96
+
97
+ end
98
+ end
@@ -0,0 +1,21 @@
1
+ module AppManager
2
+ module Protection
3
+ extend ActiveSupport::Concern
4
+ def authorize_request
5
+ if request.headers['token'].present? && ENV['APP_MANAGER_ACCESS_TOKEN']
6
+ if request.headers['token'] === ENV['APP_MANAGER_ACCESS_TOKEN']
7
+ else
8
+ render json: {
9
+ error: "Invalid Token ",
10
+ status: 401
11
+ }, status: 401
12
+ end
13
+ else
14
+ render json: {
15
+ error: "Missing Token in request",
16
+ status: 401
17
+ }, status: 401
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module AppManager
2
+ class Railtie < Rails::Railtie
3
+ railtie_name :app_manager
4
+
5
+ rake_tasks do
6
+ path = File.expand_path(__dir__)
7
+ Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ module AppManager
2
+ module Actions
3
+ class ResponseCache
4
+ def initialize(cache_path)
5
+ @cache_path = cache_path
6
+ @expires_in = AppManager.configuration.expires_in || 1.day
7
+ end
8
+
9
+ def present?
10
+ cached_response.present?
11
+ end
12
+
13
+ def body
14
+ cached_response['body']
15
+ end
16
+
17
+ def status
18
+ cached_response['status']
19
+ end
20
+
21
+ def headers
22
+ cached_response['headers']
23
+ end
24
+
25
+ def cached_response
26
+ @cached_response ||= Rails.cache.read(@cache_path)
27
+ end
28
+
29
+ def write_cache(response)
30
+ cache_object = {
31
+ body: response.body,
32
+ status: response.status,
33
+ headers: response.headers
34
+ }.as_json
35
+ Rails.cache.write(@cache_path, cache_object, expires_in: @expires_in)
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ namespace :sync do
2
+ desc "This task sync local pending charge with app manager portal"
3
+ task local_app_manager: :environment do
4
+ begin
5
+ @fs = AppManager::FailSafe.new
6
+ @fs.sync_app_manager
7
+ puts "app manager sync successfully"
8
+ rescue Exception => e
9
+ Rails.logger.info "APP MANAGER SYNC TAKS FAILED #{e.inspect}"
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppManager
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/app_manager.rb CHANGED
@@ -2,11 +2,31 @@
2
2
 
3
3
  require "httparty"
4
4
  require "rails"
5
+ require 'sqlite3'
5
6
  require "app_manager/version"
6
7
  require "app_manager/engine"
7
8
  require "app_manager/client"
8
-
9
+ require "app_manager/actions"
10
+ require "app_manager/api_cache_handler"
11
+ require "app_manager/graphql_helper"
12
+ require "app_manager/response_cache"
13
+ require "app_manager/config"
14
+ require "app_manager/protection"
15
+ require "app_manager/model"
16
+ require "app_manager/fail_safe"
17
+ require 'app_manager/railtie' if defined?(Rails)
9
18
 
10
19
  module AppManager
11
- # Your code goes here...
20
+ def self.configure
21
+ yield configuration
22
+ end
23
+
24
+ def self.configuration
25
+ @configuration ||= AppManager::Config.new
26
+ end
27
+
28
+ def self.clear_cache
29
+ Rails.cache.delete_matched('api-response-cache/*')
30
+ end
31
+
12
32
  end
@@ -8,6 +8,14 @@ module AppManager
8
8
  route("mount AppManager::Engine, at: '/'")
9
9
  end
10
10
 
11
+ # def create_initializer_file
12
+ # copy_file("plan_features.rb", "config/initializers/plan_features.rb")
13
+ # end
14
+
15
+ def create_app_manager_initializer
16
+ template("app_manager.rb", "config/initializers/app_manager.rb")
17
+ end
18
+
11
19
  end
12
20
  end
13
21
  end
@@ -0,0 +1,61 @@
1
+ AppManager.configure do |config|
2
+ config.enable_caching = false # Optional, True to enable app-manager api response caching, default is enabled from gem
3
+ config.expires_in = 1.days # Optional, Example: 30.seconds, 5.minutes or 2.days Default caching is for 1.days from gem
4
+ config.app_url = '' # App URL like https://volumediscount.hulkapps.dev/ or #https://5044-2409-4052-209a-69da-9d7-925a-9418-a9c3.ngrok.io
5
+ config.shopify_api_key = '' # Shopify api key of app
6
+ config.shopify_api_version = '' # Must be 2022-04 or latest
7
+ config.shopify_table_name = 'shops' # Table name which is generated by shopify mostly it is 'shops'
8
+ config.shopify_domain_field = 'shopify_domain' #shopify domain field
9
+ config.plan_id_or_name_field = 'plan_id'
10
+ config.field_names = {
11
+ 'name' => 'shopify_domain', # demo-rahul-tiwari.myshopify.com
12
+ 'shopify_email' => 'email', # rahul.t@hulkapps.com
13
+ 'shopify_token' => 'shopify_token',
14
+ 'shopify_plan' => 'plan_name', # partner_test
15
+ 'plan_id' => 'plan_id', # 1. t
16
+ 'created_at' => 'created_at', # 2022-04-15 10:43:05
17
+ 'trial_activated_at' => 'trial_activated_at' # field name that stores trial start/activated date
18
+ }
19
+ config.plan_features = [
20
+ {
21
+ "uuid" => "b48a3a6c-c1fb-11ec-9d64-0242ac120002",
22
+ "name" => "Features 1",
23
+ "slug" => "feature-1",
24
+ "description" => "Feature Description",
25
+ "value_type" => "integer",
26
+ "format" => "count",
27
+ "display_order" => 1
28
+ },
29
+ {
30
+ "uuid" => "9f18f95a-bfaf-11ec-9d64-0242ac120002",
31
+ "name" => "Features 2",
32
+ "slug" => "feature-2",
33
+ "description" => "Feature Description",
34
+ "value_type" => "boolean",
35
+ "format" => "percentage",
36
+ "display_order" => 2
37
+ },
38
+ {
39
+ "uuid" => "9f190a26-bfaf-11ec-9d64-0242ac120002",
40
+ "name" => "Features 3",
41
+ "slug" => "feature-3",
42
+ "description" => "Feature Description",
43
+ "value_type" => "string",
44
+ "format" => "string",
45
+ "display_order" => 3
46
+ },
47
+ {
48
+ "uuid" => "9f191340-bfaf-11ec-9d64-0242ac12000",
49
+ "name" => "Features 4",
50
+ "slug" => "feature-4",
51
+ "description" => "Feature Description",
52
+ "value_type" => "array",
53
+ "values" => [
54
+ "val 1",
55
+ "val 2"
56
+ ],
57
+ "format" => "string",
58
+ "display_order" => 4
59
+ }
60
+ ] #Required, Values type : integer, boolean, string, array
61
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hulkapps
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-29 00:00:00.000000000 Z
11
+ date: 2022-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 5.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: kaminari
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.16.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.16.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.0
41
69
  description: Provides helper function to access AppManager API
42
70
  email: rahul.t@hulkapps.com
43
71
  executables: []
@@ -54,17 +82,33 @@ files:
54
82
  - Rakefile
55
83
  - app/controllers/app_manager/application_controller.rb
56
84
  - app/controllers/app_manager/banners_controller.rb
85
+ - app/controllers/app_manager/charges_controller.rb
86
+ - app/controllers/app_manager/plans_controller.rb
87
+ - app/controllers/concerns/app_manager/authenticate.rb
88
+ - app_manager-0.1.0.gem
57
89
  - app_manager.gemspec
58
90
  - bin/console
59
91
  - bin/setup
60
92
  - config/routes.rb
61
93
  - lib/app_manager.rb
94
+ - lib/app_manager/actions.rb
95
+ - lib/app_manager/api_cache_handler.rb
62
96
  - lib/app_manager/client.rb
63
97
  - lib/app_manager/client/banners.rb
64
98
  - lib/app_manager/client/connection.rb
99
+ - lib/app_manager/client/plans.rb
100
+ - lib/app_manager/config.rb
65
101
  - lib/app_manager/engine.rb
102
+ - lib/app_manager/fail_safe.rb
103
+ - lib/app_manager/graphql_helper.rb
104
+ - lib/app_manager/model.rb
105
+ - lib/app_manager/protection.rb
106
+ - lib/app_manager/railtie.rb
107
+ - lib/app_manager/response_cache.rb
108
+ - lib/app_manager/tasks/sync/local_app_manager.rake
66
109
  - lib/app_manager/version.rb
67
110
  - lib/generators/app_manager/install/install_generator.rb
111
+ - lib/generators/app_manager/install/templates/app_manager.rb.tt
68
112
  homepage: https://www.hulkapps.com
69
113
  licenses: []
70
114
  metadata: {}