app_manager 0.1.0 → 1.0.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.
@@ -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: {}