disco_app 0.5.6 → 0.6.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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/disco_app/icon.svg +1 -0
  3. data/app/assets/stylesheets/disco_app/{bootstrap-custom.scss → bootstrap/_custom.scss} +3 -4
  4. data/app/assets/stylesheets/disco_app/bootstrap/_variables.scss +872 -0
  5. data/app/assets/stylesheets/disco_app/disco/_buttons.scss +31 -0
  6. data/app/assets/stylesheets/disco_app/disco/_cards.scss +43 -0
  7. data/app/assets/stylesheets/disco_app/disco/_forms.scss +23 -0
  8. data/app/assets/stylesheets/disco_app/disco/_sections.scss +61 -0
  9. data/app/assets/stylesheets/disco_app/disco/_type.scss +21 -0
  10. data/app/assets/stylesheets/disco_app/disco/mixins/_flexbox.scss +394 -0
  11. data/app/assets/stylesheets/disco_app/disco_app.scss +12 -6
  12. data/app/controllers/disco_app/authenticated_controller.rb +1 -1
  13. data/app/controllers/disco_app/install_controller.rb +1 -1
  14. data/app/controllers/disco_app/webhooks_controller.rb +11 -9
  15. data/app/jobs/disco_app/app_installed_job.rb +1 -1
  16. data/app/jobs/disco_app/app_uninstalled_job.rb +2 -17
  17. data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +19 -0
  18. data/app/jobs/disco_app/shop_job.rb +1 -1
  19. data/app/jobs/disco_app/shop_update_job.rb +1 -1
  20. data/app/models/disco_app/concerns/plan.rb +14 -0
  21. data/app/models/disco_app/concerns/shop.rb +62 -0
  22. data/app/models/disco_app/concerns/subscription.rb +14 -0
  23. data/app/models/disco_app/plan.rb +3 -0
  24. data/app/models/disco_app/session_storage.rb +18 -0
  25. data/app/models/disco_app/shop.rb +2 -43
  26. data/app/models/disco_app/subscription.rb +3 -0
  27. data/app/services/disco_app/subscription_service.rb +25 -0
  28. data/app/services/disco_app/webhook_service.rb +30 -0
  29. data/app/views/disco_app/shared/_card.html.erb +16 -0
  30. data/app/views/disco_app/shared/_section.html.erb +17 -0
  31. data/{lib/generators/disco_app/templates → app}/views/layouts/embedded_app.html.erb +14 -6
  32. data/db/migrate/20150525000000_create_shops_if_not_existent.rb +15 -0
  33. data/db/migrate/20151017231302_create_disco_app_plans.rb +13 -0
  34. data/db/migrate/20151017232027_create_disco_app_subscriptions.rb +15 -0
  35. data/db/migrate/20151017234409_move_shop_to_disco_app_engine.rb +5 -0
  36. data/lib/disco_app/engine.rb +5 -0
  37. data/lib/disco_app/version.rb +1 -1
  38. data/lib/generators/disco_app/disco_app_generator.rb +31 -54
  39. data/lib/generators/disco_app/mailify/mailify_generator.rb +55 -0
  40. data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +7 -0
  41. data/test/controllers/disco_app/install_controller_test.rb +50 -0
  42. data/test/controllers/disco_app/webhooks_controller_test.rb +58 -0
  43. data/test/controllers/home_controller_test.rb +61 -0
  44. data/test/dummy/app/assets/javascripts/application.js +4 -0
  45. data/test/dummy/app/assets/stylesheets/application.scss +5 -0
  46. data/test/dummy/app/controllers/application_controller.rb +1 -0
  47. data/test/dummy/app/controllers/home_controller.rb +7 -0
  48. data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +11 -0
  49. data/test/dummy/app/models/disco_app/shop.rb +15 -0
  50. data/test/dummy/app/views/home/index.html.erb +2 -0
  51. data/test/dummy/config/application.rb +11 -0
  52. data/test/dummy/config/environments/production.rb +7 -1
  53. data/test/dummy/config/initializers/disco_app.rb +1 -0
  54. data/test/dummy/config/initializers/omniauth.rb +9 -0
  55. data/test/dummy/config/initializers/shopify_app.rb +7 -0
  56. data/test/dummy/config/initializers/shopify_session_repository.rb +7 -0
  57. data/test/dummy/config/routes.rb +5 -1
  58. data/test/dummy/config/secrets.yml +2 -2
  59. data/test/dummy/db/schema.rb +70 -0
  60. data/test/fixtures/api/widget_store/shop.json +46 -0
  61. data/test/fixtures/disco_app/plans.yml +32 -0
  62. data/test/fixtures/disco_app/shops.yml +10 -0
  63. data/test/fixtures/disco_app/subscriptions.yml +26 -0
  64. data/test/fixtures/webhooks/app_uninstalled.json +46 -0
  65. data/test/jobs/disco_app/app_installed_job_test.rb +29 -0
  66. data/test/jobs/disco_app/app_uninstalled_job_test.rb +32 -0
  67. data/test/models/disco_app/plan_test.rb +5 -0
  68. data/test/models/disco_app/shop_test.rb +26 -0
  69. data/test/models/disco_app/subscription_test.rb +6 -0
  70. data/test/services/disco_app/subscription_service_test.rb +28 -0
  71. data/test/support/test_file_fixtures.rb +29 -0
  72. data/test/test_helper.rb +32 -1
  73. metadata +148 -30
  74. data/app/assets/stylesheets/disco_app/bootstrap-variables.scss +0 -12
  75. data/lib/generators/disco_app/templates/jobs/app_installed_job.rb +0 -2
  76. data/lib/generators/disco_app/templates/jobs/app_uninstalled_job.rb +0 -2
  77. data/lib/generators/disco_app/templates/jobs/shop_update_job.rb +0 -2
  78. data/lib/generators/disco_app/templates/models/shop.rb +0 -3
  79. data/test/dummy/README.rdoc +0 -28
  80. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  81. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  82. data/test/lib/generators/disco_app/disco_app_generator_test.rb +0 -16
  83. /data/{lib/generators/disco_app/templates → app}/views/layouts/application.html.erb +0 -0
  84. /data/{lib/generators/disco_app/templates → app}/views/sessions/new.html.erb +0 -0
@@ -0,0 +1,58 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::WebhooksControllerTest < ActionController::TestCase
4
+ include ActiveJob::TestHelper
5
+
6
+ def setup
7
+ @shop = disco_app_shops(:widget_store)
8
+ @routes = DiscoApp::Engine.routes
9
+ end
10
+
11
+ def teardown
12
+ @shop = nil
13
+ end
14
+
15
+ test 'webhook request without authentication information returns unauthorized' do
16
+ body = webhook_fixture('app_uninstalled')
17
+ post(:process_webhook, body)
18
+ assert_response :unauthorized
19
+ end
20
+
21
+ test 'webhook request with no HMAC returns unauthorized' do
22
+ body = webhook_fixture('app_uninstalled')
23
+ @request.headers['HTTP_X_SHOPIFY_TOPIC'] = :'app/uninstalled'
24
+ @request.headers['HTTP_X_SHOPIFY_SHOP_DOMAIN'] = @shop.shopify_domain
25
+ post(:process_webhook, body)
26
+ assert_response :unauthorized
27
+ end
28
+
29
+ test 'webhook request with invalid HMAC returns unauthorized' do
30
+ body = webhook_fixture('app_uninstalled')
31
+ @request.headers['HTTP_X_SHOPIFY_TOPIC'] = :'app/uninstalled'
32
+ @request.headers['HTTP_X_SHOPIFY_SHOP_DOMAIN'] = @shop.shopify_domain
33
+ @request.headers['HTTP_X_SHOPIFY_HMAC_SHA256'] = '0000'
34
+ post(:process_webhook, body)
35
+ assert_response :unauthorized
36
+ end
37
+
38
+ test 'webhook request with valid HMAC returns OK' do
39
+ body = webhook_fixture('app_uninstalled')
40
+ @request.headers['HTTP_X_SHOPIFY_TOPIC'] = :'app/uninstalled'
41
+ @request.headers['HTTP_X_SHOPIFY_SHOP_DOMAIN'] = @shop.shopify_domain
42
+ @request.headers['HTTP_X_SHOPIFY_HMAC_SHA256'] = DiscoApp::WebhookService.calculated_hmac(body, ShopifyApp.configuration.secret)
43
+ post(:process_webhook, body)
44
+ assert_response :ok
45
+ end
46
+
47
+ test 'app uninstalled job queued when app/uninstalled webhook arrives' do
48
+ body = webhook_fixture('app_uninstalled')
49
+ @request.headers['HTTP_X_SHOPIFY_TOPIC'] = :'app/uninstalled'
50
+ @request.headers['HTTP_X_SHOPIFY_SHOP_DOMAIN'] = @shop.shopify_domain
51
+ @request.headers['HTTP_X_SHOPIFY_HMAC_SHA256'] = DiscoApp::WebhookService.calculated_hmac(body, ShopifyApp.configuration.secret)
52
+
53
+ assert_enqueued_with(job: DiscoApp::AppUninstalledJob) do
54
+ post(:process_webhook, body)
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,61 @@
1
+ require 'test_helper'
2
+
3
+ class HomeControllerTest < ActionController::TestCase
4
+
5
+ def setup
6
+ @shop = disco_app_shops(:widget_store)
7
+ log_in_as(@shop)
8
+ end
9
+
10
+ def teardown
11
+ @shop = nil
12
+ end
13
+
14
+ test 'non-logged in user is redirected to the login page' do
15
+ log_out
16
+ get(:index)
17
+ assert_redirected_to ShopifyApp::Engine.routes.url_helpers.login_path
18
+ end
19
+
20
+ test 'logged-in, never installed user is redirected to the install page' do
21
+ get(:index)
22
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.install_path
23
+ end
24
+
25
+ test 'logged-in, awaiting install user is redirected to the installing page' do
26
+ @shop.awaiting_install!
27
+ get(:index)
28
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.installing_path
29
+ end
30
+
31
+ test 'logged-in, installing user is redirected to the installing page' do
32
+ @shop.installing!
33
+ get(:index)
34
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.installing_path
35
+ end
36
+
37
+ test 'logged-in, installed user is able to access the page' do
38
+ @shop.installed!
39
+ get(:index)
40
+ assert_response :success
41
+ end
42
+
43
+ test 'logged-in, awaiting uninstall user is redirected to the uninstalling page' do
44
+ @shop.awaiting_uninstall!
45
+ get(:index)
46
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.uninstalling_path
47
+ end
48
+
49
+ test 'logged-in, uninstalling user is redirected to the uninstalling page' do
50
+ @shop.uninstalling!
51
+ get(:index)
52
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.uninstalling_path
53
+ end
54
+
55
+ test 'logged-in, uninstalled user is redirected to the install page' do
56
+ @shop.uninstalled!
57
+ get(:index)
58
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.install_path
59
+ end
60
+
61
+ end
@@ -10,4 +10,8 @@
10
10
  // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
11
  // about supported directives.
12
12
  //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require turbolinks
16
+ //= require disco_app/disco_app
13
17
  //= require_tree .
@@ -0,0 +1,5 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ */
5
+ @import "disco_app/disco_app";
@@ -1,4 +1,5 @@
1
1
  class ApplicationController < ActionController::Base
2
+ include ShopifyApp::Controller
2
3
  # Prevent CSRF attacks by raising an exception.
3
4
  # For APIs, you may want to use :null_session instead.
4
5
  protect_from_forgery with: :exception
@@ -0,0 +1,7 @@
1
+ class HomeController < ApplicationController
2
+ include DiscoApp::AuthenticatedController
3
+
4
+ def index
5
+ end
6
+
7
+ end
@@ -0,0 +1,11 @@
1
+ class DiscoApp::AppUninstalledJob < DiscoApp::ShopJob
2
+ include DiscoApp::Concerns::AppUninstalledJob
3
+
4
+ # Extend the perform method to change the country name of the shop to
5
+ # 'Nowhere' on uninstallation.
6
+ def perform(domain, shop_data)
7
+ super(domain, shop_data)
8
+ @shop.update(country_name: 'Nowhere')
9
+ end
10
+
11
+ end
@@ -0,0 +1,15 @@
1
+ require 'active_utils'
2
+
3
+ class DiscoApp::Shop < ActiveRecord::Base
4
+ include DiscoApp::Concerns::Shop
5
+
6
+ # Extend the Shop model to return the Shop's country as an ActiveUtils country.
7
+ def country
8
+ begin
9
+ ActiveUtils::Country.find(country_name)
10
+ rescue ActiveUtils::InvalidCountryCodeError
11
+ nil
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,2 @@
1
+ <% provide(:title, 'Welcome') %>
2
+ <h1>Welcome</h1>
@@ -7,6 +7,8 @@ require "disco_app"
7
7
 
8
8
  module Dummy
9
9
  class Application < Rails::Application
10
+ config.action_dispatch.default_headers['P3P'] = 'CP="Not used"'
11
+ config.action_dispatch.default_headers.delete('X-Frame-Options')
10
12
  # Settings in config/environments/* take precedence over those specified here.
11
13
  # Application configuration should go into files in config/initializers
12
14
  # -- all .rb files in that directory are automatically loaded.
@@ -19,6 +21,15 @@ module Dummy
19
21
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20
22
  # config.i18n.default_locale = :de
21
23
 
24
+ # Set the name of the application
25
+ config.x.shopify_app_name = ENV['SHOPIFY_APP_NAME']
26
+
27
+ # Set the default host for absolute URL routing purposes
28
+ routes.default_url_options[:host] = ENV['DEFAULT_HOST']
29
+
30
+ # Explicitly prevent real charges being created by default
31
+ config.x.shopify_charges_real = false
32
+
22
33
  # Do not swallow errors in after_commit/after_rollback callbacks.
23
34
  config.active_record.raise_in_transactional_callbacks = true
24
35
  end
@@ -1,6 +1,12 @@
1
1
  Rails.application.configure do
2
2
  # Settings specified here will take precedence over those in config/application.rb.
3
3
 
4
+ # Use Sidekiq as the active job backend
5
+ config.active_job.queue_adapter = :sidekiq
6
+
7
+ # Allow real charges in production with an ENV variable
8
+ config.x.shopify_charges_real = ENV['SHOPIFY_CHARGES_REAL'] == 'true'
9
+
4
10
  # Code is not reloaded between requests.
5
11
  config.cache_classes = true
6
12
 
@@ -42,7 +48,7 @@ Rails.application.configure do
42
48
  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
43
49
 
44
50
  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
45
- # config.force_ssl = true
51
+ config.force_ssl = true
46
52
 
47
53
  # Use the lowest log level to ensure availability of diagnostic information
48
54
  # when problems arise.
@@ -0,0 +1 @@
1
+ DiscoApp::Engine.routes.default_url_options[:host] = ENV['DEFAULT_HOST']
@@ -0,0 +1,9 @@
1
+ Rails.application.config.middleware.use OmniAuth::Builder do
2
+ provider :shopify,
3
+ ShopifyApp.configuration.api_key,
4
+ ShopifyApp.configuration.secret,
5
+
6
+ :redirect_uri => ShopifyApp.configuration.redirect_uri,
7
+
8
+ :scope => ShopifyApp.configuration.scope
9
+ end
@@ -0,0 +1,7 @@
1
+ ShopifyApp.configure do |config|
2
+ config.api_key = ENV['SHOPIFY_APP_API_KEY']
3
+ config.secret = ENV['SHOPIFY_APP_SECRET']
4
+ config.redirect_uri = ENV['SHOPIFY_APP_REDIRECT_URI']
5
+ config.scope = ENV['SHOPIFY_APP_SCOPE']
6
+ config.embedded_app = true
7
+ end
@@ -0,0 +1,7 @@
1
+ if Rails.configuration.cache_classes
2
+ ShopifyApp::SessionRepository.storage = DiscoApp::SessionStorage
3
+ else
4
+ ActionDispatch::Reloader.to_prepare do
5
+ ShopifyApp::SessionRepository.storage = DiscoApp::SessionStorage
6
+ end
7
+ end
@@ -1,4 +1,8 @@
1
1
  Rails.application.routes.draw do
2
2
 
3
- mount DiscoApp::Engine => "/disco_app"
3
+ root to: 'home#index'
4
+
5
+ mount ShopifyApp::Engine, at: '/'
6
+ mount DiscoApp::Engine, at: '/'
7
+
4
8
  end
@@ -11,10 +11,10 @@
11
11
  # if you're sharing your code publicly.
12
12
 
13
13
  development:
14
- secret_key_base: 0e1841198c57175ce98403fb97e7b9f7fd80c3b4ca054d29622d4772d7378b8e8a63b59f2b774710171be2d739e4e08c73cedb59f123f1b7c04a22cf04e0084c
14
+ secret_key_base: 0cddddfcccc53c82114d3f0c81ce603461c02d1ff661b2508e599f408416b4fe7525cfe0c91e2bf84cacc5c72daa2e6836ef2e8af05d2bb138e116713da7db24
15
15
 
16
16
  test:
17
- secret_key_base: 5723516c8f90ebb81751e175f05f9b72df1c5dd3ac88aa7aaef2cae1617f029979af02a0ac0505a6999c9f257372b784048697a806ab62e2c9ac5f3ee65db017
17
+ secret_key_base: fbdd6a5a671bb1d6592648b96321f95b115b25ef198cdb5147c5ad48c0a349dcd5346a6a72ac0d3c4d13dcf16bc052c7ef2ec08254f0a519b78bedb4a6bc0d96
18
18
 
19
19
  # Do not keep production secrets in the repository,
20
20
  # instead read values from the environment.
@@ -0,0 +1,70 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20151017234409) do
15
+
16
+ create_table "disco_app_plans", force: :cascade do |t|
17
+ t.integer "status"
18
+ t.string "name"
19
+ t.integer "charge_type"
20
+ t.decimal "default_price"
21
+ t.integer "default_trial_days"
22
+ t.datetime "created_at", null: false
23
+ t.datetime "updated_at", null: false
24
+ end
25
+
26
+ create_table "disco_app_shops", force: :cascade do |t|
27
+ t.string "shopify_domain", null: false
28
+ t.string "shopify_token", null: false
29
+ t.datetime "created_at"
30
+ t.datetime "updated_at"
31
+ t.integer "status", default: 0
32
+ t.string "email"
33
+ t.string "country_name"
34
+ t.string "currency"
35
+ t.string "money_format"
36
+ t.string "money_with_currency_format"
37
+ t.string "domain"
38
+ t.string "plan_name"
39
+ t.integer "charge_status", default: 6
40
+ t.string "plan_display_name"
41
+ t.decimal "latitude"
42
+ t.decimal "longitude"
43
+ t.string "customer_email"
44
+ t.boolean "password_enabled"
45
+ t.string "phone"
46
+ t.string "primary_locale"
47
+ t.string "ships_to_countries"
48
+ t.string "timezone"
49
+ t.string "iana_timezone"
50
+ t.boolean "has_storefront"
51
+ end
52
+
53
+ add_index "disco_app_shops", ["shopify_domain"], name: "index_disco_app_shops_on_shopify_domain", unique: true
54
+
55
+ create_table "disco_app_subscriptions", force: :cascade do |t|
56
+ t.integer "shop_id"
57
+ t.integer "plan_id"
58
+ t.integer "status"
59
+ t.string "name"
60
+ t.integer "charge_type"
61
+ t.decimal "price"
62
+ t.integer "trial_days"
63
+ t.datetime "created_at", null: false
64
+ t.datetime "updated_at", null: false
65
+ end
66
+
67
+ add_index "disco_app_subscriptions", ["plan_id"], name: "index_disco_app_subscriptions_on_plan_id"
68
+ add_index "disco_app_subscriptions", ["shop_id"], name: "index_disco_app_subscriptions_on_shop_id"
69
+
70
+ end
@@ -0,0 +1,46 @@
1
+ {
2
+ "shop": {
3
+ "id": 3788917,
4
+ "name": "ONE INCH ROUND ® ",
5
+ "email": "gavin@gavinballard.com",
6
+ "domain": "one-inch-round-development.myshopify.com",
7
+ "created_at": "2014-02-19T11:50:27-08:00",
8
+ "province": "Oregon",
9
+ "country": "US",
10
+ "address1": "4016 SE Division St. #A",
11
+ "zip": "97202",
12
+ "city": "Portland",
13
+ "source": null,
14
+ "phone": "5032338003",
15
+ "updated_at": "2015-10-07T14:35:47-07:00",
16
+ "customer_email": null,
17
+ "latitude": 45.5048,
18
+ "longitude": -122.621,
19
+ "primary_location_id": null,
20
+ "primary_locale": "en",
21
+ "country_code": "US",
22
+ "country_name": "United States",
23
+ "currency": "USD",
24
+ "timezone": "(GMT-08:00) Pacific Time (US & Canada)",
25
+ "iana_timezone": "America/Los_Angeles",
26
+ "shop_owner": "Gavin Ballard",
27
+ "money_format": "${{amount}}",
28
+ "money_with_currency_format": "${{amount}} USD",
29
+ "province_code": "OR",
30
+ "taxes_included": false,
31
+ "tax_shipping": null,
32
+ "county_taxes": true,
33
+ "plan_display_name": "affiliate",
34
+ "plan_name": "affiliate",
35
+ "myshopify_domain": "one-inch-round-development.myshopify.com",
36
+ "google_apps_domain": null,
37
+ "google_apps_login_enabled": null,
38
+ "money_in_emails_format": "${{amount}}",
39
+ "money_with_currency_in_emails_format": "${{amount}} USD",
40
+ "eligible_for_payments": true,
41
+ "requires_extra_payments_agreement": false,
42
+ "password_enabled": false,
43
+ "has_storefront": true,
44
+ "setup_required": false
45
+ }
46
+ }
@@ -0,0 +1,32 @@
1
+ development:
2
+ status: 2
3
+ name: Development
4
+ charge_type: 0
5
+ default_price: 0.00
6
+ default_trial_days: 14
7
+
8
+ comped:
9
+ status: 2
10
+ name: Comped
11
+ charge_type: 0
12
+ default_price: 0.00
13
+ default_trial_days: 0
14
+
15
+ cheapo:
16
+ status: 1
17
+ name: Cheapo
18
+ charge_type: 0
19
+ default_price: 0.99
20
+ default_trial_days: 14
21
+
22
+ basic:
23
+ name: Basic
24
+ charge_type: 0
25
+ default_price: 9.99
26
+ default_trial_days: 14
27
+
28
+ premium:
29
+ name: Premium
30
+ charge_type: 0
31
+ default_price: 49.99
32
+ default_trial_days: 14
@@ -0,0 +1,10 @@
1
+ widget_store:
2
+ shopify_domain: widgets.myshopify.com
3
+ shopify_token: 00000000000000000000000000000000
4
+ country_name: Australia
5
+
6
+ widget_store_dev:
7
+ shopify_domain: widgets-dev.myshopify.com
8
+ shopify_token: 00000000000000000000000000000000
9
+ status: 3
10
+ country_name: Australia
@@ -0,0 +1,26 @@
1
+ widget_store_old:
2
+ shop: widget_store
3
+ plan: cheapo
4
+ status: <%= DiscoApp::Subscription.statuses[:replaced] %>
5
+ name: Cheapo
6
+ charge_type: 0
7
+ price: 0.99
8
+ trial_days: 14
9
+
10
+ widget_store:
11
+ shop: widget_store
12
+ plan: basic
13
+ status: <%= DiscoApp::Subscription.statuses[:active] %>
14
+ name: Basic
15
+ charge_type: 0
16
+ price: 9.99
17
+ trial_days: 14
18
+
19
+ widget_store_dev:
20
+ shop: widget_store_dev
21
+ plan: development
22
+ status: <%= DiscoApp::Subscription.statuses[:active] %>
23
+ name: Development
24
+ charge_type: 0
25
+ price: 0.00
26
+ trial_days: 0
@@ -0,0 +1,46 @@
1
+ {
2
+ "shop": {
3
+ "id": 3788917,
4
+ "name": "ONE INCH ROUND ® ",
5
+ "email": "gavin@gavinballard.com",
6
+ "domain": "one-inch-round-development.myshopify.com",
7
+ "created_at": "2014-02-19T11:50:27-08:00",
8
+ "province": "Oregon",
9
+ "country": "US",
10
+ "address1": "4016 SE Division St. #A",
11
+ "zip": "97202",
12
+ "city": "Portland",
13
+ "source": null,
14
+ "phone": "5032338003",
15
+ "updated_at": "2015-10-07T14:35:47-07:00",
16
+ "customer_email": null,
17
+ "latitude": 45.5048,
18
+ "longitude": -122.621,
19
+ "primary_location_id": null,
20
+ "primary_locale": "en",
21
+ "country_code": "US",
22
+ "country_name": "United States",
23
+ "currency": "USD",
24
+ "timezone": "(GMT-08:00) Pacific Time (US & Canada)",
25
+ "iana_timezone": "America/Los_Angeles",
26
+ "shop_owner": "Gavin Ballard",
27
+ "money_format": "${{amount}}",
28
+ "money_with_currency_format": "${{amount}} USD",
29
+ "province_code": "OR",
30
+ "taxes_included": false,
31
+ "tax_shipping": null,
32
+ "county_taxes": true,
33
+ "plan_display_name": "affiliate",
34
+ "plan_name": "affiliate",
35
+ "myshopify_domain": "one-inch-round-development.myshopify.com",
36
+ "google_apps_domain": null,
37
+ "google_apps_login_enabled": null,
38
+ "money_in_emails_format": "${{amount}}",
39
+ "money_with_currency_in_emails_format": "${{amount}} USD",
40
+ "eligible_for_payments": true,
41
+ "requires_extra_payments_agreement": false,
42
+ "password_enabled": false,
43
+ "has_storefront": true,
44
+ "setup_required": false
45
+ }
46
+ }
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::AppInstalledJobTest < ActionController::TestCase
4
+ include ActiveJob::TestHelper
5
+
6
+ def setup
7
+ @shop = disco_app_shops(:widget_store)
8
+ end
9
+
10
+ def teardown
11
+ @shop = nil
12
+ end
13
+
14
+ test 'app installed job performs shop update job' do
15
+ stub_request(:post, "#{@shop.admin_url}/webhooks.json").to_return(status: 200)
16
+ stub_request(:get, "#{@shop.admin_url}/shop.json").to_return(status: 200, body: api_fixture('widget_store/shop'))
17
+
18
+ # Assert the main install job can be enqueued and performed.
19
+ perform_enqueued_jobs do
20
+ DiscoApp::AppInstalledJob.perform_later(@shop.shopify_domain)
21
+ end
22
+ assert_performed_jobs 1
23
+
24
+ # Assert the update shop job was performed.
25
+ @shop.reload
26
+ assert_equal 'United States', @shop.country_name
27
+ end
28
+
29
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::AppUninstalledJobTest < ActionController::TestCase
4
+ include ActiveJob::TestHelper
5
+
6
+ def setup
7
+ @shop = disco_app_shops(:widget_store)
8
+ @shop.charge_active!
9
+
10
+ perform_enqueued_jobs do
11
+ DiscoApp::AppUninstalledJob.perform_later(@shop.shopify_domain, {})
12
+ end
13
+ end
14
+
15
+ def teardown
16
+ @shop = nil
17
+ end
18
+
19
+ test 'app uninstalled job changes shop status' do
20
+ assert_performed_jobs 1
21
+ @shop.reload
22
+ assert @shop.uninstalled?
23
+ end
24
+
25
+ test 'app uninstalled job can be extended using concerns' do
26
+ assert_performed_jobs 1
27
+ @shop.reload
28
+ assert @shop.charge_cancelled? # Assert base methods still called.
29
+ assert_equal 'Nowhere', @shop.country_name # Assert extended method called.
30
+ end
31
+
32
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::PlanTest < ActiveSupport::TestCase
4
+
5
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::ShopTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @shop = disco_app_shops(:widget_store)
7
+ end
8
+
9
+ def teardown
10
+ @shop = nil
11
+ end
12
+
13
+ test 'shops can be extended via concerns' do
14
+ assert_equal 'Australia', @shop.country.name
15
+ end
16
+
17
+ test 'can fetch a list of all of a shops subscriptions' do
18
+ assert_equal 2, @shop.subscriptions.size
19
+ end
20
+
21
+ test 'can fetch a shops active subscription' do
22
+ assert_equal 1, @shop.subscriptions.active.size
23
+ assert_equal disco_app_subscriptions(:widget_store), @shop.subscriptions.active.first
24
+ end
25
+
26
+ end
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::SubscriptionTest < ActiveSupport::TestCase
4
+
5
+ end
6
+
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::SubscriptionServiceTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @shop = disco_app_shops(:widget_store)
7
+ @current_subscription = @shop.current_subscription
8
+ end
9
+
10
+ def teardown
11
+ @shop = nil
12
+ end
13
+
14
+ test 'subscribing to a new plan deactivates current subscription and swaps to new plan' do
15
+ DiscoApp::SubscriptionService.subscribe(@shop, disco_app_plans(:premium))
16
+ @current_subscription.reload
17
+ assert @current_subscription.replaced?
18
+ assert_equal disco_app_plans(:premium), @shop.current_subscription.plan
19
+ end
20
+
21
+ test 'cancelling a plan works' do
22
+ DiscoApp::SubscriptionService.cancel(@shop)
23
+ @current_subscription.reload
24
+ assert @current_subscription.cancelled?
25
+ assert_not @shop.current_subscription
26
+ end
27
+
28
+ end