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.
- checksums.yaml +5 -5
- data/app/assets/images/disco_app/logo.png +0 -0
- data/app/clients/disco_app/rollbar_client.rb +53 -0
- data/app/clients/disco_app/rollbar_client_error.rb +2 -0
- data/app/controllers/disco_app/concerns/app_proxy_controller.rb +1 -1
- data/app/controllers/disco_app/concerns/authenticated_controller.rb +10 -1
- data/app/controllers/disco_app/concerns/user_authenticated_controller.rb +2 -2
- data/app/controllers/disco_app/user_sessions_controller.rb +1 -1
- data/app/controllers/disco_app/webhooks_controller.rb +1 -1
- data/app/controllers/sessions_controller.rb +1 -1
- data/app/jobs/application_job.rb +2 -0
- data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +26 -9
- data/app/jobs/disco_app/shop_job.rb +1 -1
- data/app/models/application_record.rb +3 -0
- data/app/models/disco_app/app_settings.rb +1 -1
- data/app/models/disco_app/application_charge.rb +8 -2
- data/app/models/disco_app/concerns/can_be_liquified.rb +5 -4
- data/app/models/disco_app/concerns/plan.rb +12 -3
- data/app/models/disco_app/concerns/plan_code.rb +4 -1
- data/app/models/disco_app/concerns/shop.rb +9 -1
- data/app/models/disco_app/concerns/subscription.rb +11 -4
- data/app/models/disco_app/concerns/synchronises.rb +1 -1
- data/app/models/disco_app/plan.rb +1 -1
- data/app/models/disco_app/plan_code.rb +1 -1
- data/app/models/disco_app/recurring_application_charge.rb +9 -2
- data/app/models/disco_app/shop.rb +1 -1
- data/app/models/disco_app/source.rb +1 -1
- data/app/models/disco_app/subscription.rb +1 -1
- data/app/models/disco_app/user.rb +1 -1
- data/app/services/disco_app/partner_app_service.rb +151 -0
- data/db/migrate/20150525000000_create_shops_if_not_existent.rb +1 -1
- data/db/migrate/20170315062548_create_disco_app_sources.rb +1 -1
- data/db/migrate/20170315062629_add_sources_to_shop_subscriptions.rb +1 -1
- data/db/migrate/20170327214540_create_disco_app_users.rb +1 -1
- data/db/migrate/20170606160751_fix_disco_app_users_index.rb +1 -1
- data/lib/disco_app/version.rb +1 -1
- data/lib/generators/disco_app/disco_app_generator.rb +17 -18
- data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +2 -1
- data/lib/generators/disco_app/templates/root/README.md +26 -0
- data/lib/tasks/partner_app.rake +26 -0
- data/lib/tasks/rollbar.rake +24 -0
- data/test/controllers/disco_app/charges_controller_test.rb +11 -11
- data/test/controllers/disco_app/subscriptions_controller_test.rb +4 -4
- data/test/controllers/disco_app/webhooks_controller_test.rb +5 -5
- data/test/controllers/home_controller_test.rb +1 -1
- data/test/controllers/proxy_controller_test.rb +3 -3
- data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +1 -1
- data/test/dummy/app/controllers/proxy_controller.rb +1 -1
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/cart.rb +1 -1
- data/test/dummy/app/models/disco_app/shop.rb +1 -1
- data/test/dummy/app/models/js_configuration.rb +1 -1
- data/test/dummy/app/models/product.rb +1 -1
- data/test/dummy/app/models/widget_configuration.rb +1 -1
- data/test/dummy/config/application.rb +0 -3
- data/test/dummy/config/environments/test.rb +2 -2
- data/test/dummy/config/initializers/shopify_session_repository.rb +1 -1
- data/test/dummy/db/migrate/20160307182229_create_products.rb +2 -2
- data/test/dummy/db/migrate/20160530160739_create_asset_models.rb +2 -2
- data/test/dummy/db/migrate/20161105054746_create_carts.rb +3 -2
- data/test/dummy/db/schema.rb +89 -96
- data/test/fixtures/disco_app/shops.yml +6 -2
- data/test/fixtures/liquid/model.liquid +8 -8
- data/test/integration/synchronises_test.rb +15 -9
- data/test/jobs/disco_app/synchronise_webhooks_job_test.rb +16 -4
- data/test/test_helper.rb +13 -0
- data/test/vcr/webhook_failure.yml +640 -0
- metadata +81 -38
data/test/dummy/db/schema.rb
CHANGED
@@ -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.
|
21
|
-
t.string
|
22
|
-
t.jsonb
|
23
|
-
t.datetime "created_at",
|
24
|
-
t.datetime "updated_at",
|
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.
|
36
|
-
t.
|
37
|
-
t.integer
|
38
|
-
t.datetime "created_at",
|
39
|
-
t.datetime "updated_at",
|
40
|
-
t.
|
41
|
-
t.string
|
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.
|
46
|
-
t.string
|
47
|
-
t.integer
|
48
|
-
t.integer
|
49
|
-
t.datetime "created_at",
|
50
|
-
t.datetime "updated_at",
|
51
|
-
t.integer
|
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
|
56
|
-
t.string
|
57
|
-
t.integer
|
58
|
-
t.integer
|
59
|
-
t.datetime "created_at",
|
60
|
-
t.datetime "updated_at",
|
61
|
-
t.integer
|
62
|
-
t.string
|
63
|
-
t.integer
|
64
|
-
t.integer
|
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.
|
69
|
-
t.
|
70
|
-
t.integer
|
71
|
-
t.datetime "created_at",
|
72
|
-
t.datetime "updated_at",
|
73
|
-
t.
|
74
|
-
t.string
|
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
|
79
|
-
t.text
|
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
|
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
|
90
|
-
t.string
|
91
|
-
t.datetime "created_at",
|
92
|
-
t.datetime "updated_at",
|
93
|
-
t.integer
|
94
|
-
t.string
|
95
|
-
t.string
|
96
|
-
t.string
|
97
|
-
t.jsonb
|
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
|
104
|
-
t.string
|
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
|
113
|
-
t.integer
|
114
|
-
t.integer
|
115
|
-
t.integer
|
116
|
-
t.datetime "created_at",
|
117
|
-
t.datetime "updated_at",
|
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
|
122
|
-
t.
|
123
|
-
t.integer
|
124
|
-
t.
|
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.
|
132
|
-
t.string
|
133
|
-
t.string
|
134
|
-
t.string
|
135
|
-
t.datetime "created_at",
|
136
|
-
t.datetime "updated_at",
|
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
|
-
|
140
|
-
|
141
|
-
|
142
|
-
t.
|
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.
|
149
|
-
t.jsonb
|
150
|
-
t.datetime "created_at",
|
151
|
-
t.datetime "updated_at",
|
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.
|
156
|
-
t.string
|
157
|
-
t.string
|
158
|
-
t.string
|
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:
|
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:
|
14
|
+
data:
|
15
|
+
country_name: 'Sweden'
|
16
|
+
primary_locale: 'sv'
|
@@ -1,8 +1,8 @@
|
|
1
|
-
{
|
2
|
-
{
|
3
|
-
{
|
4
|
-
{
|
5
|
-
{
|
6
|
-
{
|
7
|
-
{
|
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'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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
|