disco_app 0.5.6 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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