disco_app 0.13.6.pre.puma.pre.3 → 0.14.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.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/images/disco_app/logo.png +0 -0
  3. data/app/clients/disco_app/rollbar_client.rb +53 -0
  4. data/app/clients/disco_app/rollbar_client_error.rb +2 -0
  5. data/app/controllers/disco_app/concerns/app_proxy_controller.rb +1 -1
  6. data/app/controllers/disco_app/concerns/authenticated_controller.rb +10 -1
  7. data/app/controllers/disco_app/concerns/user_authenticated_controller.rb +2 -2
  8. data/app/controllers/disco_app/user_sessions_controller.rb +1 -1
  9. data/app/controllers/disco_app/webhooks_controller.rb +1 -1
  10. data/app/controllers/sessions_controller.rb +1 -1
  11. data/app/jobs/application_job.rb +2 -0
  12. data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +26 -9
  13. data/app/jobs/disco_app/shop_job.rb +1 -1
  14. data/app/models/application_record.rb +3 -0
  15. data/app/models/disco_app/app_settings.rb +1 -1
  16. data/app/models/disco_app/application_charge.rb +8 -2
  17. data/app/models/disco_app/concerns/can_be_liquified.rb +5 -4
  18. data/app/models/disco_app/concerns/plan.rb +12 -3
  19. data/app/models/disco_app/concerns/plan_code.rb +4 -1
  20. data/app/models/disco_app/concerns/shop.rb +9 -1
  21. data/app/models/disco_app/concerns/subscription.rb +11 -4
  22. data/app/models/disco_app/concerns/synchronises.rb +1 -1
  23. data/app/models/disco_app/plan.rb +1 -1
  24. data/app/models/disco_app/plan_code.rb +1 -1
  25. data/app/models/disco_app/recurring_application_charge.rb +9 -2
  26. data/app/models/disco_app/shop.rb +1 -1
  27. data/app/models/disco_app/source.rb +1 -1
  28. data/app/models/disco_app/subscription.rb +1 -1
  29. data/app/models/disco_app/user.rb +1 -1
  30. data/app/services/disco_app/partner_app_service.rb +151 -0
  31. data/db/migrate/20150525000000_create_shops_if_not_existent.rb +1 -1
  32. data/db/migrate/20170315062548_create_disco_app_sources.rb +1 -1
  33. data/db/migrate/20170315062629_add_sources_to_shop_subscriptions.rb +1 -1
  34. data/db/migrate/20170327214540_create_disco_app_users.rb +1 -1
  35. data/db/migrate/20170606160751_fix_disco_app_users_index.rb +1 -1
  36. data/lib/disco_app/version.rb +1 -1
  37. data/lib/generators/disco_app/disco_app_generator.rb +17 -18
  38. data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +2 -1
  39. data/lib/generators/disco_app/templates/root/README.md +26 -0
  40. data/lib/tasks/partner_app.rake +26 -0
  41. data/lib/tasks/rollbar.rake +24 -0
  42. data/test/controllers/disco_app/charges_controller_test.rb +11 -11
  43. data/test/controllers/disco_app/subscriptions_controller_test.rb +4 -4
  44. data/test/controllers/disco_app/webhooks_controller_test.rb +5 -5
  45. data/test/controllers/home_controller_test.rb +1 -1
  46. data/test/controllers/proxy_controller_test.rb +3 -3
  47. data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +1 -1
  48. data/test/dummy/app/controllers/proxy_controller.rb +1 -1
  49. data/test/dummy/app/jobs/application_job.rb +2 -0
  50. data/test/dummy/app/models/application_record.rb +3 -0
  51. data/test/dummy/app/models/cart.rb +1 -1
  52. data/test/dummy/app/models/disco_app/shop.rb +1 -1
  53. data/test/dummy/app/models/js_configuration.rb +1 -1
  54. data/test/dummy/app/models/product.rb +1 -1
  55. data/test/dummy/app/models/widget_configuration.rb +1 -1
  56. data/test/dummy/config/application.rb +0 -3
  57. data/test/dummy/config/environments/test.rb +2 -2
  58. data/test/dummy/config/initializers/shopify_session_repository.rb +1 -1
  59. data/test/dummy/db/migrate/20160307182229_create_products.rb +2 -2
  60. data/test/dummy/db/migrate/20160530160739_create_asset_models.rb +2 -2
  61. data/test/dummy/db/migrate/20161105054746_create_carts.rb +3 -2
  62. data/test/dummy/db/schema.rb +89 -96
  63. data/test/fixtures/disco_app/shops.yml +6 -2
  64. data/test/fixtures/liquid/model.liquid +8 -8
  65. data/test/integration/synchronises_test.rb +15 -9
  66. data/test/jobs/disco_app/synchronise_webhooks_job_test.rb +16 -4
  67. data/test/test_helper.rb +13 -0
  68. data/test/vcr/webhook_failure.yml +640 -0
  69. metadata +81 -38
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # This file is auto-generated from the current state of the database. Instead
3
2
  # of editing this file, please use the migrations feature of Active Record to
4
3
  # incrementally modify your database, and then regenerate this schema definition.
@@ -16,146 +15,140 @@ ActiveRecord::Schema.define(version: 20170606160751) do
16
15
  # These are extensions that must be enabled in order to support this database
17
16
  enable_extension "plpgsql"
18
17
 
19
- create_table "carts", force: :cascade do |t|
20
- t.integer "shop_id", limit: 8
21
- t.string "token"
22
- t.jsonb "data"
23
- t.datetime "created_at", null: false
24
- t.datetime "updated_at", null: false
18
+ create_table "carts", id: :serial, force: :cascade do |t|
19
+ t.bigint "shop_id"
20
+ t.string "token"
21
+ t.jsonb "data"
22
+ t.datetime "created_at", null: false
23
+ t.datetime "updated_at", null: false
24
+ t.index ["token"], name: "index_carts_on_token", unique: true
25
25
  end
26
26
 
27
- add_index "carts", ["token"], name: "index_carts_on_token", unique: true, using: :btree
28
-
29
27
  create_table "disco_app_app_settings", force: :cascade do |t|
30
28
  t.datetime "created_at", null: false
31
29
  t.datetime "updated_at", null: false
32
30
  end
33
31
 
34
32
  create_table "disco_app_application_charges", force: :cascade do |t|
35
- t.integer "shop_id", limit: 8
36
- t.integer "subscription_id", limit: 8
37
- t.integer "status", default: 0
38
- t.datetime "created_at", null: false
39
- t.datetime "updated_at", null: false
40
- t.integer "shopify_id", limit: 8
41
- t.string "confirmation_url"
33
+ t.bigint "shop_id"
34
+ t.bigint "subscription_id"
35
+ t.integer "status", default: 0
36
+ t.datetime "created_at", null: false
37
+ t.datetime "updated_at", null: false
38
+ t.bigint "shopify_id"
39
+ t.string "confirmation_url"
42
40
  end
43
41
 
44
42
  create_table "disco_app_plan_codes", force: :cascade do |t|
45
- t.integer "plan_id", limit: 8
46
- t.string "code"
47
- t.integer "trial_period_days"
48
- t.integer "amount"
49
- t.datetime "created_at", null: false
50
- t.datetime "updated_at", null: false
51
- t.integer "status", default: 0
43
+ t.bigint "plan_id"
44
+ t.string "code"
45
+ t.integer "trial_period_days"
46
+ t.integer "amount"
47
+ t.datetime "created_at", null: false
48
+ t.datetime "updated_at", null: false
49
+ t.integer "status", default: 0
52
50
  end
53
51
 
54
52
  create_table "disco_app_plans", force: :cascade do |t|
55
- t.integer "status", default: 0
56
- t.string "name"
57
- t.integer "plan_type", default: 0
58
- t.integer "trial_period_days"
59
- t.datetime "created_at", null: false
60
- t.datetime "updated_at", null: false
61
- t.integer "amount", default: 0
62
- t.string "currency", default: "USD"
63
- t.integer "interval", default: 0
64
- t.integer "interval_count", default: 1
53
+ t.integer "status", default: 0
54
+ t.string "name"
55
+ t.integer "plan_type", default: 0
56
+ t.integer "trial_period_days"
57
+ t.datetime "created_at", null: false
58
+ t.datetime "updated_at", null: false
59
+ t.integer "amount", default: 0
60
+ t.string "currency", default: "USD"
61
+ t.integer "interval", default: 0
62
+ t.integer "interval_count", default: 1
65
63
  end
66
64
 
67
65
  create_table "disco_app_recurring_application_charges", force: :cascade do |t|
68
- t.integer "shop_id", limit: 8
69
- t.integer "subscription_id", limit: 8
70
- t.integer "status", default: 0
71
- t.datetime "created_at", null: false
72
- t.datetime "updated_at", null: false
73
- t.integer "shopify_id", limit: 8
74
- t.string "confirmation_url"
66
+ t.bigint "shop_id"
67
+ t.bigint "subscription_id"
68
+ t.integer "status", default: 0
69
+ t.datetime "created_at", null: false
70
+ t.datetime "updated_at", null: false
71
+ t.bigint "shopify_id"
72
+ t.string "confirmation_url"
75
73
  end
76
74
 
77
75
  create_table "disco_app_sessions", force: :cascade do |t|
78
- t.string "session_id", null: false
79
- t.text "data"
76
+ t.string "session_id", null: false
77
+ t.text "data"
80
78
  t.datetime "created_at", null: false
81
79
  t.datetime "updated_at", null: false
82
- t.integer "shop_id"
80
+ t.integer "shop_id"
81
+ t.index ["session_id"], name: "index_disco_app_sessions_on_session_id", unique: true
82
+ t.index ["updated_at"], name: "index_disco_app_sessions_on_updated_at"
83
83
  end
84
84
 
85
- add_index "disco_app_sessions", ["session_id"], name: "index_disco_app_sessions_on_session_id", unique: true, using: :btree
86
- add_index "disco_app_sessions", ["updated_at"], name: "index_disco_app_sessions_on_updated_at", using: :btree
87
-
88
85
  create_table "disco_app_shops", force: :cascade do |t|
89
- t.string "shopify_domain", null: false
90
- t.string "shopify_token", null: false
91
- t.datetime "created_at", null: false
92
- t.datetime "updated_at", null: false
93
- t.integer "status", default: 0
94
- t.string "domain"
95
- t.string "plan_name"
96
- t.string "name"
97
- t.jsonb "data", default: {}
86
+ t.string "shopify_domain", null: false
87
+ t.string "shopify_token", null: false
88
+ t.datetime "created_at", null: false
89
+ t.datetime "updated_at", null: false
90
+ t.integer "status", default: 0
91
+ t.string "domain"
92
+ t.string "plan_name"
93
+ t.string "name"
94
+ t.jsonb "data", default: {}
95
+ t.index ["shopify_domain"], name: "index_disco_app_shops_on_shopify_domain", unique: true
98
96
  end
99
97
 
100
- add_index "disco_app_shops", ["shopify_domain"], name: "index_disco_app_shops_on_shopify_domain", unique: true, using: :btree
101
-
102
98
  create_table "disco_app_sources", force: :cascade do |t|
103
- t.string "source"
104
- t.string "name"
99
+ t.string "source"
100
+ t.string "name"
105
101
  t.datetime "created_at", null: false
106
102
  t.datetime "updated_at", null: false
103
+ t.index ["source"], name: "index_disco_app_sources_on_source"
107
104
  end
108
105
 
109
- add_index "disco_app_sources", ["source"], name: "index_disco_app_sources_on_source", using: :btree
110
-
111
106
  create_table "disco_app_subscriptions", force: :cascade do |t|
112
- t.integer "shop_id"
113
- t.integer "plan_id"
114
- t.integer "status"
115
- t.integer "subscription_type"
116
- t.datetime "created_at", null: false
117
- t.datetime "updated_at", null: false
107
+ t.integer "shop_id"
108
+ t.integer "plan_id"
109
+ t.integer "status"
110
+ t.integer "subscription_type"
111
+ t.datetime "created_at", null: false
112
+ t.datetime "updated_at", null: false
118
113
  t.datetime "trial_start_at"
119
114
  t.datetime "trial_end_at"
120
115
  t.datetime "cancelled_at"
121
- t.integer "amount", default: 0
122
- t.integer "plan_code_id", limit: 8
123
- t.integer "trial_period_days"
124
- t.integer "source_id", limit: 8
116
+ t.integer "amount", default: 0
117
+ t.bigint "plan_code_id"
118
+ t.integer "trial_period_days"
119
+ t.bigint "source_id"
120
+ t.index ["plan_id"], name: "index_disco_app_subscriptions_on_plan_id"
121
+ t.index ["shop_id"], name: "index_disco_app_subscriptions_on_shop_id"
125
122
  end
126
123
 
127
- add_index "disco_app_subscriptions", ["plan_id"], name: "index_disco_app_subscriptions_on_plan_id", using: :btree
128
- add_index "disco_app_subscriptions", ["shop_id"], name: "index_disco_app_subscriptions_on_shop_id", using: :btree
129
-
130
124
  create_table "disco_app_users", force: :cascade do |t|
131
- t.integer "shop_id", limit: 8
132
- t.string "first_name"
133
- t.string "last_name"
134
- t.string "email"
135
- t.datetime "created_at", null: false
136
- t.datetime "updated_at", null: false
125
+ t.bigint "shop_id"
126
+ t.string "first_name"
127
+ t.string "last_name"
128
+ t.string "email"
129
+ t.datetime "created_at", null: false
130
+ t.datetime "updated_at", null: false
131
+ t.index ["id", "shop_id"], name: "index_disco_app_users_on_id_and_shop_id", unique: true
137
132
  end
138
133
 
139
- add_index "disco_app_users", ["id", "shop_id"], name: "index_disco_app_users_on_id_and_shop_id", unique: true, using: :btree
140
-
141
- create_table "js_configurations", force: :cascade do |t|
142
- t.integer "shop_id", limit: 8
143
- t.string "label", default: "Default"
144
- t.string "locale", default: "en"
134
+ create_table "js_configurations", id: :serial, force: :cascade do |t|
135
+ t.bigint "shop_id"
136
+ t.string "label", default: "Default"
137
+ t.string "locale", default: "en"
145
138
  end
146
139
 
147
- create_table "products", force: :cascade do |t|
148
- t.integer "shop_id", limit: 8
149
- t.jsonb "data"
150
- t.datetime "created_at", null: false
151
- t.datetime "updated_at", null: false
140
+ create_table "products", id: :serial, force: :cascade do |t|
141
+ t.bigint "shop_id"
142
+ t.jsonb "data"
143
+ t.datetime "created_at", null: false
144
+ t.datetime "updated_at", null: false
152
145
  end
153
146
 
154
- create_table "widget_configurations", force: :cascade do |t|
155
- t.integer "shop_id", limit: 8
156
- t.string "label", default: "Default"
157
- t.string "locale", default: "en"
158
- t.string "background_color", default: "#FFFFFF"
147
+ create_table "widget_configurations", id: :serial, force: :cascade do |t|
148
+ t.bigint "shop_id"
149
+ t.string "label", default: "Default"
150
+ t.string "locale", default: "en"
151
+ t.string "background_color", default: "#FFFFFF"
159
152
  end
160
153
 
161
154
  add_foreign_key "carts", "disco_app_shops", column: "shop_id"
@@ -3,10 +3,14 @@ widget_store:
3
3
  shopify_token: 00000000000000000000000000000000
4
4
  created_at: "2017-03-07T06:06:25.000Z"
5
5
  updated_at: "2017-03-07T06:06:25.000Z"
6
- data: '{ "country_name": "Australia", "timezone": "(GMT+10:00) Melbourne" }'
6
+ data:
7
+ country_name: 'Australia'
8
+ timezone: '(GMT+10:00) Melbourne'
7
9
 
8
10
  widget_store_dev:
9
11
  shopify_domain: widgets-dev.myshopify.com
10
12
  shopify_token: 00000000000000000000000000000000
11
13
  status: 3
12
- data: '{ "country_name": "Sweden", "primary_locale": "sv" }'
14
+ data:
15
+ country_name: 'Sweden'
16
+ primary_locale: 'sv'
@@ -1,8 +1,8 @@
1
- {% assign model_numeric = 42 %}
2
- {% assign model_boolean = true %}
3
- {% assign model_empty = nil %}
4
- {% assign model_string = 'The cat's pyjamas are "great".' %}
5
- {% assign model_string_html = 'The cat&#39;s pyjamas are <strong style="color: red;">great</strong>.' %}
6
- {% assign model_array_of_numerics = '1@!@2@!@3' | split: '@!@' %}
7
- {% assign model_array_of_strings = 'A@!@B@!@C' | split: '@!@' %}
8
- {% assign model_hash = '{}' %}
1
+ {%- assign model_numeric = 42 -%}
2
+ {%- assign model_boolean = true -%}
3
+ {%- assign model_empty = nil -%}
4
+ {%- assign model_string = 'The cat&#39;s pyjamas are &quot;great&quot;.' -%}
5
+ {%- assign model_string_html = 'The cat&#39;s pyjamas are <strong style="color: red;">great</strong>.' -%}
6
+ {%- assign model_array_of_numerics = '1@!@2@!@3' | split: '@!@' -%}
7
+ {%- assign model_array_of_strings = 'A@!@B@!@C' | split: '@!@' -%}
8
+ {%- assign model_hash = '{}' -%}
@@ -1,6 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class SynchronisesTest < ActionDispatch::IntegrationTest
4
+ include ActiveJob::TestHelper
4
5
  fixtures :all
5
6
 
6
7
  def setup
@@ -14,7 +15,9 @@ class SynchronisesTest < ActionDispatch::IntegrationTest
14
15
  end
15
16
 
16
17
  test 'new product is created when product created webhook is received' do
17
- post_webhook('product_created', :'products/create')
18
+ perform_enqueued_jobs do
19
+ post_webhook('product_created', :'products/create')
20
+ end
18
21
 
19
22
  # Assert the product was created locally, with the correct attributes.
20
23
  product = Product.find(632910392)
@@ -24,7 +27,9 @@ class SynchronisesTest < ActionDispatch::IntegrationTest
24
27
  test 'existing product is updated when product updated webhook is received' do
25
28
  assert_equal({}, @product.data)
26
29
 
27
- post_webhook('product_updated', :'products/update')
30
+ perform_enqueued_jobs do
31
+ post_webhook('product_updated', :'products/update')
32
+ end
28
33
 
29
34
  # Assert the product was updated locally, with the correct attributes.
30
35
  @product.reload
@@ -33,12 +38,17 @@ class SynchronisesTest < ActionDispatch::IntegrationTest
33
38
  end
34
39
 
35
40
  test 'existing product is deleted when product deleted webhook is received' do
36
- post_webhook('product_deleted', :'products/delete')
41
+ perform_enqueued_jobs do
42
+ post_webhook('product_deleted', :'products/delete')
43
+ end
44
+
37
45
  assert_equal 0, Product.count
38
46
  end
39
47
 
40
48
  test 'cart with token for id is updated when cart updated webhook is received' do
41
- post_webhook('cart_updated', :'carts/update')
49
+ perform_enqueued_jobs do
50
+ post_webhook('cart_updated', :'carts/update')
51
+ end
42
52
 
43
53
  # Assert the cart data was correctly updated
44
54
  assert_equal 3200.0, carts(:cart).total_price
@@ -64,11 +74,7 @@ class SynchronisesTest < ActionDispatch::IntegrationTest
64
74
 
65
75
  def post_webhook(fixture_name, webhook_topic)
66
76
  body = webhook_fixture(fixture_name)
67
- post(webhooks_url, body, {
68
- HTTP_X_SHOPIFY_TOPIC: webhook_topic,
69
- HTTP_X_SHOPIFY_SHOP_DOMAIN: @shop.shopify_domain,
70
- HTTP_X_SHOPIFY_HMAC_SHA256: DiscoApp::WebhookService.calculated_hmac(body, ShopifyApp.configuration.secret)
71
- })
77
+ post webhooks_url, params: body, headers: { HTTP_X_SHOPIFY_TOPIC: webhook_topic, HTTP_X_SHOPIFY_SHOP_DOMAIN: @shop.shopify_domain, HTTP_X_SHOPIFY_HMAC_SHA256: DiscoApp::WebhookService.calculated_hmac(body, ShopifyApp.configuration.secret) }
72
78
  end
73
79
 
74
80
  end
@@ -5,18 +5,17 @@ class DiscoApp::SynchroniseWebhooksJobTest < ActionController::TestCase
5
5
 
6
6
  def setup
7
7
  @shop = disco_app_shops(:widget_store)
8
-
9
- stub_request(:get, "#{@shop.admin_url}/webhooks.json").to_return(status: 200, body: api_fixture('widget_store/webhooks').to_json)
10
- stub_request(:post, "#{@shop.admin_url}/webhooks.json").to_return(status: 200)
11
8
  end
12
9
 
13
10
  def teardown
14
11
  @shop = nil
15
-
16
12
  WebMock.reset!
17
13
  end
18
14
 
19
15
  test 'webhook synchronisation job creates webhooks for all expected topics' do
16
+ stub_request(:get, "#{@shop.admin_url}/webhooks.json").to_return(status: 200, body: api_fixture('widget_store/webhooks').to_json)
17
+ stub_request(:post, "#{@shop.admin_url}/webhooks.json").to_return(status: 200)
18
+
20
19
  perform_enqueued_jobs do
21
20
  DiscoApp::SynchroniseWebhooksJob.perform_later(@shop)
22
21
  end
@@ -27,4 +26,17 @@ class DiscoApp::SynchroniseWebhooksJobTest < ActionController::TestCase
27
26
  end
28
27
  end
29
28
 
29
+ test 'returns error messages for webhooks that cannot be registered' do
30
+ VCR.use_cassette('webhook_failure') do
31
+ output = capture_io do
32
+ perform_enqueued_jobs do
33
+ DiscoApp::SynchroniseWebhooksJob.perform_later(@shop)
34
+ end
35
+ end
36
+
37
+ assert output.first.include?('Invalid topic specified.')
38
+ assert output.first.include?('orders/create - not registered')
39
+ end
40
+ end
41
+
30
42
  end
data/test/test_helper.rb CHANGED
@@ -37,6 +37,19 @@ if ActiveSupport::TestCase.respond_to?(:fixture_path=)
37
37
  ActiveSupport::TestCase.fixtures :all
38
38
  end
39
39
 
40
+ # Add VCR to allow the recording and playback of HTTP Requests and Responses
41
+ require 'vcr'
42
+ VCR.configure do |config|
43
+ config.cassette_library_dir = 'test/vcr'
44
+ config.hook_into :webmock
45
+ config.default_cassette_options = { match_requests_on: [:method, :uri, :body], decode_compressed_response: true }
46
+ end
47
+
48
+ # Minitest helpers to give a better formatted and more helpful output in Rubymine
49
+ require 'minitest/reporters'
50
+ require 'minitest/autorun'
51
+ MiniTest::Reporters.use!
52
+
40
53
  # Set up the base test class.
41
54
  class ActiveSupport::TestCase
42
55