disco_app 0.12.1 → 0.12.5
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/app/assets/components/shopify/buttons/_buttons.scss +1 -0
- data/app/clients/disco_app/api_client.rb +27 -0
- data/app/clients/disco_app/disco_api_error.rb +2 -0
- data/app/controllers/disco_app/admin/application_controller.rb +7 -0
- data/app/controllers/disco_app/concerns/authenticated_controller.rb +15 -0
- data/app/controllers/sessions_controller.rb +6 -1
- data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +1 -0
- data/app/jobs/disco_app/concerns/subscription_changed_job.rb +1 -0
- data/app/jobs/disco_app/send_subscription_job.rb +7 -0
- data/app/models/disco_app/concerns/shop.rb +10 -0
- data/app/models/disco_app/concerns/subscription.rb +6 -0
- data/app/services/disco_app/request_validation_service.rb +15 -0
- data/app/views/shopify_app/sessions/new.html.erb +42 -0
- data/config/routes.rb +1 -0
- data/lib/disco_app/version.rb +1 -1
- data/lib/generators/disco_app/templates/initializers/rollbar.rb +4 -0
- data/lib/generators/disco_app/templates/initializers/shopify_app.rb +0 -1
- data/lib/tasks/api.rake +10 -0
- data/test/clients/disco_app/api_client_test.rb +22 -0
- data/test/controllers/home_controller_test.rb +10 -1
- data/test/dummy/app/controllers/application_controller.rb +1 -1
- data/test/dummy/config/initializers/omniauth.rb +0 -2
- data/test/dummy/config/initializers/shopify_app.rb +0 -1
- data/test/fixtures/api/subscriptions/valid_request.json +40 -0
- data/test/fixtures/disco_app/recurring_application_charges.yml +2 -0
- data/test/fixtures/disco_app/shops.yml +2 -0
- data/test/fixtures/disco_app/subscriptions.yml +3 -0
- data/test/jobs/disco_app/app_installed_job_test.rb +1 -1
- data/test/jobs/disco_app/app_uninstalled_job_test.rb +4 -4
- data/test/jobs/disco_app/send_subscription_job_test.rb +24 -0
- data/test/test_helper.rb +1 -0
- metadata +21 -4
- data/app/views/sessions/new.html.erb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca27fe14e53f4e34f76940c75b601e8534f3b0fc30a2fc668951793e0ab05846
|
4
|
+
data.tar.gz: def89441dbebd476d9efac4889b6854ff2e5e32d7192154b391b4d8144da26ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bce10166c303ac988305dee9c40acb2d7ce05eff63c368144f3941784e7ef51e970c42b8350702b0e3075f65e8ed3a56ef99921d8705edea4b00c263e0cac2e
|
7
|
+
data.tar.gz: 73055ae6330d43924b75aaad82044afe09ecffb91964b7a13b2e3b2d9b748619af3a541adf0877d1820d93bed717416b62312d003219f6b2526eb9ef3dabb41d
|
@@ -226,6 +226,7 @@
|
|
226
226
|
cursor: default;
|
227
227
|
color: transparent;
|
228
228
|
text-shadow: none;
|
229
|
+
background: #fff url(data:image/gif;base64,R0lGODlhEAAQAPUAAC8vL3Z2dpSUlKWlpa2trbW1tb29vcbGxs7OztbW1t7e3ufn5%2B%2Fv7%2Ff39%2F%2F%2F%2F%2F%2F%2F%2Fz09PXNzc4uLizk5OX9%2Ffzo6On19fZiYmEFBQW9vbzw8PEBAQGtrazU1NWdnZ4GBgSUlJWRkZJCQkD4%2BPj8%2FPy4uLo2NjQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH%2FC05FVFNDQVBFMi4wAwH%2F%2FwAh%2BQQJBgAPACwAAAAAEAAQAAAEifDJ52QJdeq3QnoC4DSFsnFAAAIPMizaAheAEbrI0yyOEwSGRkCAKAwIO2PjoQikGktK4zAowCauzCTxkRgGYNNmajBQBWixhlEoEAyTBUIrUVwlUwFy8z0wKEYIUwkNDApBCUdLdhwDCUULjg8MCVokBQ4HBA9UfxsLBDCaIwRdGiMSCAYVDVoRACH5BAkGAAAALAAAAAAQABAAAAWRICACjjhE5agCS6QAEeQ0kLECTBTBECBBB9WCATgAYwnIrrFwOCQSRCMyQBgGEMaiMGiwTpKGF9BgcAsLVcKQGiUSI2sBfWscDIY7gUBfmQsENiIMCm0iCmkjDQgDBGMjVwdEDlxSBwllCgYNCY1eiF8JCGgDcAwJbQ1zDgcERQNEKwsEaa0zBHArMyJWJQ1tIQAh%2BQQJBgAAACwAAAAAEAAQAAAFkSAgAo5ICOWoAouwABTlMJSxAvQACNQ%2BHaoFA4CgJHiJSa%2BhcDgKg0RDYFAgCBNGMoszDAqNhsjRoEwmhRQLoRZRBCOEwXAYrlrzg4FAKLxWDAUFBDYiDE0rCn8iDQgDBGIqXnUkUAgNB1KHBg0Jj2KKLFEIflE4CWoNgg4HBAAHA3ZBBC%2BtZAQJN2QiciUNaiEAIfkECQYAAAAsAAAAABAAEAAABZMgIAKOaAzlqAJMsQCD5TQWsgINUcAWXNmjBQOgGCQIF0XlglM4HIWBomE4LBIGC%2BNQqTRYp0IjNbN0DSnAApEWXQYjhKE6XC0slwvBQNC9VkpdFSMMTit7Kg0IAwRfKicHQ1ADCA0HCQ2FBg0JjF8KLwtGCC5GLAlpDQUFDgcEAAcDdSoLBC%2BuMwQJNzMiciVjIyEAIfkECQYAAAAsAAAAABAAEAAABZEgIAKOiBjlqAJMwQAH4TRDsgINYcADUGQK1eKlGCgOg0WmgFM4HAVjw4BgKBASBiKTabAMg0IjNZNgMogUYJFeEZgmg%2BHwWi0kXImB8F7cFBkYZyNWaiIFByoNCAMEXiMOggMvUAMIDQcJDQwJGXeCXgp%2BCzUIBaQ7CQNqDQUFDjE8dUIEfjEzBDYrM3ElYyMhACH5BAkGAAAALAAAAAAQABAAAAWSICACjogY5agCTMEAB%2BE0hbICDWHABIAMC9XipRgoYowBArdwOArGhgHBWCgIjMSF0mAZBoVGakagXBJCRGp0OIxOhsNrxdiaDQRCIbhaUP4UIwwKayIFbiMNPwRdIw4UGhQ2T0oNBwkNCwQaCwMaGl0KQZ0JCBcFGgUACQVrNK0xAJ98QgRBMQ4LqTczJigsayEAIfkECQYAAAAsAAAAABAAEAAABZIgIAKOiBjlqAJMwQAH4TSFsgINYcAEgAwL1eKlGChijAECt3A4CsaGAcFYKAiNBbTBMgwKjdTsMCDYRgtEanRYmgyGw2vFIAy%2BBgKhEKQPJBIDIwwKayJtKg0%2FWCoOEhsSQU9KDWQKCQUcWhwcXApBC2WcBxuCR2s0BQ4cGwCsCTcLBEEbGw4LGzsrMyKcJWEjIQAh%2BQQJBgAAACwAAAAAEAAQAAAFkyAgAo6IGOWoAkzBAAfhNIWyAg1hwASADAvV4qUYKGKMAQK3cDgKxoYBwVgoCI0FtMEyDAqN1OzwDY4WiNQokRidDIfXqnEwwA0EQsGsYuR1IwwJaiZtIw0%2FHlwjDgMfAy9PXwoeQEcfDAcfH1wKQQYdBR8eCB49aGoMHR8OHh0AozYrBx02rg4MHgc3MyKjJWEjIQAh%2BQQJBgAAACwAAAAAEAAQAAAGmUCAEOAQIgzFoRLAKDAAB4KjUVAsAQ2CAUoAIAYL5eKpGCiijAECu3A4CuaGAcFYKAiNBbzBNAwKDUlTB39hQwsISUMJCUNHBgdPSw0HBpAGBAQDjUtNBVqOA4pCCoZCDCEgIHxKfpFEqiILIbILCSIMCQN4AFVQIAQiIQkhB0wJiqghDsIAwaaLIFvCDgwia0tTQgMiRYFDQQAh%2BQQJBgAAACwAAAAAEAAQAAAGmECAEOAQIgzFoRLAKDAAB4KjUVAsAQ2CAUoAIAYL5eKpGCiijAECu3A4CuaGAcFYKAiNBbzBNAwKDUlTB39hQwciSUMJCUMZIyMZa0sNBwYGiBmaB1dNBVqLBYpCCoZCDCKQfEp%2BB08OjyILIgQMDAkGDQkDeFCcCSOfImWNt4oNmg4DIgB%2BT0sLkgDLDgwEjUtTQn5FgUNBACH5BAkGAAAALAAAAAAQABAAAAaVQIAQ4BAiDMWhEsAoMAAHgqNRUCwBDYIBSgAgBgvlwfpVRBkDBHbhcERIA0bkwFgoCI1FYdAALEQkJAx9RA0HAwVhQwciSUMJCUMiEZSRS4YGBgdvgQdXTQVaQwpISwqKQg0DJBGEQwYDdERvcVoMDKQNCQN4XmoKcwaJA5EMCY4NIo0GXYdPS3%2BRzFMElkpTRqUNjkEAIfkECQYAAAAsAAAAABAAEAAABptAgBDgECIMxaESoCghAAeCo1FQLAGMUglKACAGC2XCeigRzozBs7FwODLmRiaTWCgI7MKgAUjAMw18RA0HAwVhQwcmSUMJCUMDJpJWS4QGBopzdFcMBQUEBkMLCIxCCohCDQaSgkMGAwcMRAMZBQwHCQ0MCgYNCQN4Xo8LAwkIh8VYCYxUBQ5RUAOySwsEYVFTBI9LU0ZIAA2MQQA7) 50% 50% no-repeat !important;
|
229
230
|
}
|
230
231
|
|
231
232
|
.btn:not(.btn-disabled).is-loading::before, .btn:not(.btn-disabled).is-loading:hover::before {
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
|
3
|
+
class DiscoApp::ApiClient
|
4
|
+
|
5
|
+
SUBSCRIPTION_ENDPOINT = 'app_subscriptions.json'
|
6
|
+
|
7
|
+
def initialize(shop, url)
|
8
|
+
@shop = shop
|
9
|
+
@url = url
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_app_subscription
|
13
|
+
return unless @url.present?
|
14
|
+
url = @url + SUBSCRIPTION_ENDPOINT
|
15
|
+
begin
|
16
|
+
response = RestClient::Request.execute(
|
17
|
+
method: :post,
|
18
|
+
headers: { content_type: :json },
|
19
|
+
url: url,
|
20
|
+
payload: { shop: @shop, subscription: @shop.current_subscription }.to_json
|
21
|
+
)
|
22
|
+
rescue RestClient::BadRequest, RestClient::ResourceNotFound => e
|
23
|
+
raise DiscoApiError.new(e.message)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module DiscoApp::Concerns::AuthenticatedController
|
2
2
|
extend ActiveSupport::Concern
|
3
|
+
include ShopifyApp::LoginProtection
|
3
4
|
|
4
5
|
included do
|
6
|
+
before_action :auto_login
|
5
7
|
before_action :login_again_if_different_shop
|
6
8
|
before_action :shopify_shop
|
7
9
|
before_action :check_installed
|
@@ -13,6 +15,15 @@ module DiscoApp::Concerns::AuthenticatedController
|
|
13
15
|
|
14
16
|
private
|
15
17
|
|
18
|
+
def auto_login
|
19
|
+
if shop_session.nil? and request_hmac_valid?
|
20
|
+
if(shop = DiscoApp::Shop.find_by_shopify_domain(sanitized_shop_name)).present?
|
21
|
+
session[:shopify] = shop.id
|
22
|
+
session[:shopify_domain] = sanitized_shop_name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
16
27
|
def shopify_shop
|
17
28
|
if shop_session
|
18
29
|
@shop = DiscoApp::Shop.find_by!(shopify_domain: @shop_session.url)
|
@@ -53,4 +64,8 @@ module DiscoApp::Concerns::AuthenticatedController
|
|
53
64
|
end
|
54
65
|
end
|
55
66
|
|
67
|
+
def request_hmac_valid?
|
68
|
+
DiscoApp::RequestValidationService.hmac_valid?(request.query_string, ShopifyApp.configuration.secret)
|
69
|
+
end
|
70
|
+
|
56
71
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class SessionsController < ApplicationController
|
2
|
-
include ShopifyApp::
|
2
|
+
include ShopifyApp::SessionsConcern
|
3
3
|
|
4
4
|
def referral
|
5
5
|
cookies[DiscoApp::SOURCE_COOKIE_KEY] = params[:source] if params[:source].present?
|
@@ -7,6 +7,11 @@ class SessionsController < ApplicationController
|
|
7
7
|
redirect_to root_path
|
8
8
|
end
|
9
9
|
|
10
|
+
def failure
|
11
|
+
flash[:notice] = 'There was an issue while trying to authenticate, please retry'
|
12
|
+
redirect_to root_path
|
13
|
+
end
|
14
|
+
|
10
15
|
protected
|
11
16
|
|
12
17
|
# Override the authenticate method to allow skipping OAuth in development
|
@@ -61,6 +61,11 @@ module DiscoApp::Concerns::Shop
|
|
61
61
|
"https://#{shopify_domain}/admin"
|
62
62
|
end
|
63
63
|
|
64
|
+
# Convenience method to get the email of the shop's admin, to display in Rollbar.
|
65
|
+
def email
|
66
|
+
self.data['email']
|
67
|
+
end
|
68
|
+
|
64
69
|
def installed_duration
|
65
70
|
distance_of_time_in_words_to_now(created_at.time)
|
66
71
|
end
|
@@ -81,6 +86,11 @@ module DiscoApp::Concerns::Shop
|
|
81
86
|
(data['primary_locale'] || 'en').to_sym
|
82
87
|
end
|
83
88
|
|
89
|
+
# Return an instance of the Disco API client.
|
90
|
+
def disco_api_client
|
91
|
+
@api_client ||= DiscoApp::ApiClient.new(self, ENV['DISCO_API_URL'])
|
92
|
+
end
|
93
|
+
|
84
94
|
end
|
85
95
|
|
86
96
|
end
|
@@ -47,6 +47,12 @@ module DiscoApp::Concerns::Subscription
|
|
47
47
|
recurring? ? ShopifyAPI::RecurringApplicationCharge : ShopifyAPI::ApplicationCharge
|
48
48
|
end
|
49
49
|
|
50
|
+
def as_json(options = {})
|
51
|
+
super.merge(
|
52
|
+
'active_charge' => active_charge
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
50
56
|
private
|
51
57
|
|
52
58
|
# If the amount or trial period for this subscription changes, clear any
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class DiscoApp::RequestValidationService
|
2
|
+
|
3
|
+
def self.hmac_valid?(query_string, secret)
|
4
|
+
query_hash = Rack::Utils.parse_query(query_string)
|
5
|
+
hmac = query_hash.delete('hmac').to_s
|
6
|
+
ActiveSupport::SecurityUtils.variable_size_secure_compare(self.calculated_hmac(query_hash, secret), hmac)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Return the calculated hmac for the given query hash and secret.
|
10
|
+
def self.calculated_hmac(query_hash, secret)
|
11
|
+
sorted_params = query_hash.collect{ |k, v| "#{k}=#{Array(v).join(',')}" }.sort.join('&')
|
12
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, sorted_params)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Install <%= DiscoApp.configuration.app_name %></title>
|
5
|
+
|
6
|
+
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
|
7
|
+
|
8
|
+
<%= csrf_meta_tags %>
|
9
|
+
|
10
|
+
<%= yield :extra_head %>
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
<%= form_tag shopify_app.login_path do %>
|
14
|
+
<div class="ui-empty-state">
|
15
|
+
<section class="ui-empty-state__section">
|
16
|
+
<div class="ui-empty-state__subsection">
|
17
|
+
<h1 class="ui-empty-state__title">Install <%= DiscoApp.configuration.app_name %></h1>
|
18
|
+
<h2 class="ui-empty-state__subtitle">Enter your Shopify store name below to get started.</h2>
|
19
|
+
</div>
|
20
|
+
<div class="ui-empty-state__subsection">
|
21
|
+
<div class="next-grid">
|
22
|
+
<div class="next-grid__cell" style="text-align: right;">
|
23
|
+
<label for="shop" class="next-input__help-text">https://</label>
|
24
|
+
</div>
|
25
|
+
<div class="next-grid__cell">
|
26
|
+
<input type="text" class="form-control" id="shop" name="shop" placeholder="your-store" autocomplete="off" autofocus="on" />
|
27
|
+
</div>
|
28
|
+
<div class="next-grid__cell" style="text-align: left;">
|
29
|
+
<label for="shop" class="next-input__help-text">.myshopify.com</label>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
<div class="ui-empty-state__subsection">
|
34
|
+
<button type="submit" class="btn btn-large btn-primary">Install</button>
|
35
|
+
</div>
|
36
|
+
</section>
|
37
|
+
</div>
|
38
|
+
<% end %>
|
39
|
+
|
40
|
+
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
|
41
|
+
</body>
|
42
|
+
</html>
|
data/config/routes.rb
CHANGED
data/lib/disco_app/version.rb
CHANGED
@@ -10,6 +10,10 @@ Rollbar.configure do |config|
|
|
10
10
|
# Enable delayed reporting (using Sidekiq)
|
11
11
|
config.use_sidekiq
|
12
12
|
|
13
|
+
# Enable "Person" feature of Rollbar in the context of a "Shop"
|
14
|
+
config.person_method = 'current_shop'
|
15
|
+
config.person_username_method = 'shopify_domain'
|
16
|
+
|
13
17
|
# Add custom handlers.
|
14
18
|
config.before_process << proc do |options|
|
15
19
|
if options[:exception].is_a?(ActiveResource::ClientError) and options[:exception].message.include?('Too Many Requests')
|
data/lib/tasks/api.rake
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ApiClientTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@shop = disco_app_shops(:widget_store)
|
7
|
+
stub_request(:post, "https://api.discolabs.com/v1/app_subscriptions.json").
|
8
|
+
with(body: api_fixture('subscriptions/valid_request').to_json).
|
9
|
+
to_return(status: 200, body: api_fixture('subscriptions/valid_request').to_json)
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
@shop = nil
|
14
|
+
WebMock.reset!
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'Successful disco api call render correct JSON' do
|
18
|
+
response = @shop.disco_api_client.create_app_subscription
|
19
|
+
assert_equal api_fixture('subscriptions/valid_request'), JSON.parse(response.body)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -14,7 +14,7 @@ class HomeControllerTest < ActionController::TestCase
|
|
14
14
|
@current_subscription = nil
|
15
15
|
end
|
16
16
|
|
17
|
-
test 'non-logged in user is redirected to the login page' do
|
17
|
+
test 'non-logged in user is redirected to the login page if no hmac and shop domain present' do
|
18
18
|
log_out
|
19
19
|
get(:index)
|
20
20
|
assert_redirected_to ShopifyApp::Engine.routes.url_helpers.login_path
|
@@ -89,4 +89,13 @@ class HomeControllerTest < ActionController::TestCase
|
|
89
89
|
assert_response :success
|
90
90
|
end
|
91
91
|
|
92
|
+
test 'non-logged in user is logged in if valid hmac and shop domain is present in url' do
|
93
|
+
log_out
|
94
|
+
Timecop.freeze('2017-03-08 12:44:58 +1100') do
|
95
|
+
hmac = 'eb49ba93a8daf8a11a04c66129faf98de1cd40f082b0ae78e79a2dfbbefb438d'
|
96
|
+
get(:index, { hmac: hmac, shop: 'widgets-dev.myshopify.com', timestamp: Time.now.to_i })
|
97
|
+
assert_response :success
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
92
101
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class ApplicationController < ActionController::Base
|
2
|
-
include ShopifyApp::
|
2
|
+
include ShopifyApp::LoginProtection
|
3
3
|
# Prevent CSRF attacks by raising an exception.
|
4
4
|
# For APIs, you may want to use :null_session instead.
|
5
5
|
protect_from_forgery with: :exception
|
@@ -0,0 +1,40 @@
|
|
1
|
+
{
|
2
|
+
"shop": {
|
3
|
+
"id": 605094243,
|
4
|
+
"shopify_domain": "widgets.myshopify.com",
|
5
|
+
"shopify_token": "0",
|
6
|
+
"created_at": "2017-03-07T06:06:25.000Z",
|
7
|
+
"updated_at": "2017-03-07T06:06:25.000Z",
|
8
|
+
"status": "never_installed",
|
9
|
+
"domain": null,
|
10
|
+
"plan_name": null,
|
11
|
+
"name": null,
|
12
|
+
"data": {"timezone": "(GMT+10:00) Melbourne", "country_name": "Australia"}
|
13
|
+
},
|
14
|
+
"subscription": {
|
15
|
+
"id": 304261385,
|
16
|
+
"shop_id": 605094243,
|
17
|
+
"plan_id": 276395349,
|
18
|
+
"status": "active",
|
19
|
+
"subscription_type": "recurring",
|
20
|
+
"created_at": "2017-03-07T06:06:25.000Z",
|
21
|
+
"updated_at": "2017-03-07T06:06:25.000Z",
|
22
|
+
"trial_start_at": null,
|
23
|
+
"trial_end_at": null,
|
24
|
+
"cancelled_at": null,
|
25
|
+
"amount": 999,
|
26
|
+
"plan_code_id": null,
|
27
|
+
"source": null,
|
28
|
+
"trial_period_days": 14,
|
29
|
+
"active_charge": {
|
30
|
+
"id":332186283,
|
31
|
+
"shop_id":605094243,
|
32
|
+
"subscription_id":304261385,
|
33
|
+
"status":"active",
|
34
|
+
"created_at":"2017-03-07T06:06:25.000Z",
|
35
|
+
"updated_at":"2017-03-07T06:06:25.000Z",
|
36
|
+
"shopify_id":null,
|
37
|
+
"confirmation_url":null
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
@@ -2,6 +2,8 @@ current_widget_store_subscription_recurring_charge:
|
|
2
2
|
shop: widget_store
|
3
3
|
subscription: current_widget_store_subscription
|
4
4
|
status: <%= DiscoApp::RecurringApplicationCharge.statuses[:active] %>
|
5
|
+
created_at: "2017-03-07T06:06:25.000Z"
|
6
|
+
updated_at: "2017-03-07T06:06:25.000Z"
|
5
7
|
|
6
8
|
new_widget_store_subscription_recurring_charge:
|
7
9
|
shop: widget_store
|
@@ -1,6 +1,8 @@
|
|
1
1
|
widget_store:
|
2
2
|
shopify_domain: widgets.myshopify.com
|
3
3
|
shopify_token: 00000000000000000000000000000000
|
4
|
+
created_at: "2017-03-07T06:06:25.000Z"
|
5
|
+
updated_at: "2017-03-07T06:06:25.000Z"
|
4
6
|
data: '{ "country_name": "Australia", "timezone": "(GMT+10:00) Melbourne" }'
|
5
7
|
|
6
8
|
widget_store_dev:
|
@@ -13,6 +13,9 @@ current_widget_store_subscription:
|
|
13
13
|
trial_period_days: 14
|
14
14
|
status: <%= DiscoApp::Subscription.statuses[:active] %>
|
15
15
|
subscription_type: 0
|
16
|
+
created_at: "2017-03-07T06:06:25.000Z"
|
17
|
+
updated_at: "2017-03-07T06:06:25.000Z"
|
18
|
+
|
16
19
|
|
17
20
|
current_widget_store_dev_subscription:
|
18
21
|
shop: widget_store_dev
|
@@ -11,11 +11,11 @@ class DiscoApp::AppInstalledJobTest < ActionController::TestCase
|
|
11
11
|
stub_request(:get, "#{@shop.admin_url}/shop.json").to_return(status: 200, body: api_fixture('widget_store/shop').to_json)
|
12
12
|
stub_request(:get, "#{@shop.admin_url}/carrier_services.json").to_return(status: 200, body: api_fixture('widget_store/carrier_services').to_json)
|
13
13
|
stub_request(:post, "#{@shop.admin_url}/carrier_services.json").to_return(status: 200)
|
14
|
+
stub_request(:post, "https://api.discolabs.com/v1/app_subscriptions.json").to_return(status: 200)
|
14
15
|
end
|
15
16
|
|
16
17
|
def teardown
|
17
18
|
@shop = nil
|
18
|
-
|
19
19
|
WebMock.reset!
|
20
20
|
end
|
21
21
|
|
@@ -5,7 +5,7 @@ class DiscoApp::AppUninstalledJobTest < ActionController::TestCase
|
|
5
5
|
|
6
6
|
def setup
|
7
7
|
@shop = disco_app_shops(:widget_store)
|
8
|
-
|
8
|
+
stub_request(:post, "https://api.discolabs.com/v1/app_subscriptions.json").to_return(status: 200)
|
9
9
|
perform_enqueued_jobs do
|
10
10
|
DiscoApp::AppUninstalledJob.perform_later(@shop, {})
|
11
11
|
end
|
@@ -13,18 +13,18 @@ class DiscoApp::AppUninstalledJobTest < ActionController::TestCase
|
|
13
13
|
|
14
14
|
def teardown
|
15
15
|
@shop = nil
|
16
|
+
WebMock.reset!
|
16
17
|
end
|
17
18
|
|
18
19
|
test 'app uninstalled job changes shop status' do
|
19
|
-
assert_performed_jobs
|
20
|
+
assert_performed_jobs 2
|
20
21
|
@shop.reload
|
21
22
|
assert @shop.uninstalled?
|
22
23
|
end
|
23
24
|
|
24
25
|
test 'app uninstalled job can be extended using concerns' do
|
25
|
-
assert_performed_jobs
|
26
|
+
assert_performed_jobs 2
|
26
27
|
@shop.reload
|
27
28
|
assert_equal 'Nowhere', @shop.data['country_name'] # Assert extended method called.
|
28
29
|
end
|
29
|
-
|
30
30
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DiscoApp::SendSubscriptionJobTest < ActionController::TestCase
|
4
|
+
include ActiveJob::TestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@shop = disco_app_shops(:widget_store)
|
8
|
+
stub_request(:post, "https://api.discolabs.com/v1/app_subscriptions.json").to_return(status: 200)
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@shop = nil
|
13
|
+
|
14
|
+
WebMock.reset!
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'subscription job correctly sends request to API' do
|
18
|
+
perform_enqueued_jobs do
|
19
|
+
DiscoApp::SendSubscriptionJob.perform_later(@shop)
|
20
|
+
end
|
21
|
+
assert_requested(:post, "https://api.discolabs.com/v1/app_subscriptions.json", times: 1)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -10,6 +10,7 @@ ENV['SHOPIFY_APP_SECRET'] = 'b607d1f8b992dccb017f9315f07af9c4'
|
|
10
10
|
ENV['SHOPIFY_APP_REDIRECT_URI'] = 'https://test.example.com/shopify/auth/callback'
|
11
11
|
ENV['SHOPIFY_APP_SCOPE'] = 'read_products'
|
12
12
|
ENV['SHOPIFY_CHARGES_REAL'] = 'false'
|
13
|
+
ENV['DISCO_API_URL'] = 'https://api.discolabs.com/v1/'
|
13
14
|
|
14
15
|
require File.expand_path("../../test/dummy/config/environment.rb", __FILE__)
|
15
16
|
ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../test/dummy/db/migrate", __FILE__)]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: disco_app
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gavin Ballard
|
@@ -100,14 +100,20 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '7.2'
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 7.2.3
|
104
107
|
type: :runtime
|
105
108
|
prerelease: false
|
106
109
|
version_requirements: !ruby/object:Gem::Requirement
|
107
110
|
requirements:
|
108
111
|
- - "~>"
|
109
112
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
113
|
+
version: '7.2'
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 7.2.3
|
111
117
|
- !ruby/object:Gem::Dependency
|
112
118
|
name: puma
|
113
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -526,6 +532,8 @@ files:
|
|
526
532
|
- app/assets/stylesheets/disco_app/ui-kit/_ui-layout.scss
|
527
533
|
- app/assets/stylesheets/disco_app/ui-kit/_ui-tabs.scss
|
528
534
|
- app/assets/stylesheets/disco_app/ui-kit/_ui-type.scss
|
535
|
+
- app/clients/disco_app/api_client.rb
|
536
|
+
- app/clients/disco_app/disco_api_error.rb
|
529
537
|
- app/controllers/disco_app/admin/app_settings_controller.rb
|
530
538
|
- app/controllers/disco_app/admin/application_controller.rb
|
531
539
|
- app/controllers/disco_app/admin/concerns/app_settings_controller.rb
|
@@ -558,6 +566,7 @@ files:
|
|
558
566
|
- app/jobs/disco_app/concerns/synchronise_resources_job.rb
|
559
567
|
- app/jobs/disco_app/concerns/synchronise_webhooks_job.rb
|
560
568
|
- app/jobs/disco_app/render_asset_group_job.rb
|
569
|
+
- app/jobs/disco_app/send_subscription_job.rb
|
561
570
|
- app/jobs/disco_app/shop_job.rb
|
562
571
|
- app/jobs/disco_app/shop_update_job.rb
|
563
572
|
- app/jobs/disco_app/subscription_changed_job.rb
|
@@ -587,6 +596,7 @@ files:
|
|
587
596
|
- app/services/disco_app/carrier_request_service.rb
|
588
597
|
- app/services/disco_app/charges_service.rb
|
589
598
|
- app/services/disco_app/proxy_service.rb
|
599
|
+
- app/services/disco_app/request_validation_service.rb
|
590
600
|
- app/services/disco_app/subscription_service.rb
|
591
601
|
- app/services/disco_app/webhook_service.rb
|
592
602
|
- app/views/disco_app/admin/app_settings/edit.html.erb
|
@@ -613,7 +623,7 @@ files:
|
|
613
623
|
- app/views/layouts/application.html.erb
|
614
624
|
- app/views/layouts/embedded_app.html.erb
|
615
625
|
- app/views/layouts/embedded_app_modal.html.erb
|
616
|
-
- app/views/sessions/new.html.erb
|
626
|
+
- app/views/shopify_app/sessions/new.html.erb
|
617
627
|
- config/routes.rb
|
618
628
|
- db/migrate/20150525000000_create_shops_if_not_existent.rb
|
619
629
|
- lib/disco_app.rb
|
@@ -641,12 +651,14 @@ files:
|
|
641
651
|
- lib/generators/disco_app/templates/root/CHECKS
|
642
652
|
- lib/generators/disco_app/templates/root/Procfile
|
643
653
|
- lib/generators/disco_app/templates/views/home/index.html.erb
|
654
|
+
- lib/tasks/api.rake
|
644
655
|
- lib/tasks/carrier_service.rake
|
645
656
|
- lib/tasks/database.rake
|
646
657
|
- lib/tasks/sessions.rake
|
647
658
|
- lib/tasks/shops.rake
|
648
659
|
- lib/tasks/start.rake
|
649
660
|
- lib/tasks/webhooks.rake
|
661
|
+
- test/clients/disco_app/api_client_test.rb
|
650
662
|
- test/controllers/disco_app/admin/shops_controller_test.rb
|
651
663
|
- test/controllers/disco_app/charges_controller_test.rb
|
652
664
|
- test/controllers/disco_app/install_controller_test.rb
|
@@ -718,6 +730,7 @@ files:
|
|
718
730
|
- test/dummy/public/422.html
|
719
731
|
- test/dummy/public/500.html
|
720
732
|
- test/dummy/public/favicon.ico
|
733
|
+
- test/fixtures/api/subscriptions/valid_request.json
|
721
734
|
- test/fixtures/api/widget_store/assets/create_script_tag_js_request.json
|
722
735
|
- test/fixtures/api/widget_store/assets/create_script_tag_js_response.json
|
723
736
|
- test/fixtures/api/widget_store/assets/create_script_tag_request.json
|
@@ -781,6 +794,7 @@ files:
|
|
781
794
|
- test/integration/synchronises_test.rb
|
782
795
|
- test/jobs/disco_app/app_installed_job_test.rb
|
783
796
|
- test/jobs/disco_app/app_uninstalled_job_test.rb
|
797
|
+
- test/jobs/disco_app/send_subscription_job_test.rb
|
784
798
|
- test/jobs/disco_app/synchronise_carrier_service_job_test.rb
|
785
799
|
- test/jobs/disco_app/synchronise_webhooks_job_test.rb
|
786
800
|
- test/models/disco_app/can_be_liquified_test.rb
|
@@ -884,6 +898,7 @@ test_files:
|
|
884
898
|
- test/dummy/config/database.gitlab-ci.yml
|
885
899
|
- test/dummy/config/application.rb
|
886
900
|
- test/fixtures/liquid/model.liquid
|
901
|
+
- test/fixtures/api/subscriptions/valid_request.json
|
887
902
|
- test/fixtures/api/widget_store/carrier_services.json
|
888
903
|
- test/fixtures/api/widget_store/assets/create_test_js_response.json
|
889
904
|
- test/fixtures/api/widget_store/assets/create_widget_js_response.json
|
@@ -949,6 +964,7 @@ test_files:
|
|
949
964
|
- test/disco_app_test.rb
|
950
965
|
- test/jobs/disco_app/app_uninstalled_job_test.rb
|
951
966
|
- test/jobs/disco_app/synchronise_carrier_service_job_test.rb
|
967
|
+
- test/jobs/disco_app/send_subscription_job_test.rb
|
952
968
|
- test/jobs/disco_app/synchronise_webhooks_job_test.rb
|
953
969
|
- test/jobs/disco_app/app_installed_job_test.rb
|
954
970
|
- test/controllers/disco_app/install_controller_test.rb
|
@@ -959,6 +975,7 @@ test_files:
|
|
959
975
|
- test/controllers/proxy_controller_test.rb
|
960
976
|
- test/controllers/home_controller_test.rb
|
961
977
|
- test/integration/synchronises_test.rb
|
978
|
+
- test/clients/disco_app/api_client_test.rb
|
962
979
|
- test/models/disco_app/plan_test.rb
|
963
980
|
- test/models/disco_app/has_metafields_test.rb
|
964
981
|
- test/models/disco_app/shop_test.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
<% provide(:title, "Install #{DiscoApp.configuration.app_name}") %>
|
2
|
-
|
3
|
-
<%= form_tag shopify_app.login_path do %>
|
4
|
-
<div class="ui-empty-state">
|
5
|
-
<section class="ui-empty-state__section">
|
6
|
-
<div class="ui-empty-state__subsection">
|
7
|
-
<h1 class="ui-empty-state__title">Install <%= DiscoApp.configuration.app_name %></h1>
|
8
|
-
<h2 class="ui-empty-state__subtitle">Enter your Shopify store name below to get started.</h2>
|
9
|
-
</div>
|
10
|
-
<div class="ui-empty-state__subsection">
|
11
|
-
<div class="next-grid">
|
12
|
-
<div class="next-grid__cell" style="text-align: right;">
|
13
|
-
<label for="shop" class="next-input__help-text">https://</label>
|
14
|
-
</div>
|
15
|
-
<div class="next-grid__cell">
|
16
|
-
<input type="text" class="form-control" id="shop" name="shop" placeholder="your-store" autocomplete="off" autofocus="on" />
|
17
|
-
</div>
|
18
|
-
<div class="next-grid__cell" style="text-align: left;">
|
19
|
-
<label for="shop" class="next-input__help-text">.myshopify.com</label>
|
20
|
-
</div>
|
21
|
-
</div>
|
22
|
-
</div>
|
23
|
-
<div class="ui-empty-state__subsection">
|
24
|
-
<button type="submit" class="btn btn-large btn-primary">Install</button>
|
25
|
-
</div>
|
26
|
-
</section>
|
27
|
-
</div>
|
28
|
-
<% end %>
|