disco_app 0.9.6
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 +7 -0
- data/Rakefile +37 -0
- data/app/assets/images/disco_app/icon.svg +1 -0
- data/app/assets/images/disco_app/icons.svg +0 -0
- data/app/assets/javascripts/disco_app/components/custom/filterable_shop_list.js.jsx +61 -0
- data/app/assets/javascripts/disco_app/components/custom/inline-radio-options.es6.jsx +59 -0
- data/app/assets/javascripts/disco_app/components/custom/rules-editor.es6.jsx +417 -0
- data/app/assets/javascripts/disco_app/components/custom/shop_filter_query.js.jsx +13 -0
- data/app/assets/javascripts/disco_app/components/custom/shop_filter_tab.js.jsx +34 -0
- data/app/assets/javascripts/disco_app/components/custom/shop_filter_tabs.js.jsx +21 -0
- data/app/assets/javascripts/disco_app/components/custom/shop_list.js.jsx +142 -0
- data/app/assets/javascripts/disco_app/components/custom/shop_row.js.jsx +43 -0
- data/app/assets/javascripts/disco_app/components/custom/shopify_admin_link.js.jsx +29 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/card-footer.es6.jsx +11 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/card-header.es6.jsx +11 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/card-section.es6.jsx +30 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/card.es6.jsx +16 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/cards/cart-section-title.es6.jsx +9 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_form.es6.jsx +72 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_input.es6.jsx +20 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/button.es6.jsx +13 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-radio.es6.jsx +30 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-select.es6.jsx +39 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-text.es6.jsx +59 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-textarea.es6.jsx +48 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/icons/icon-chevron.es6.jsx +33 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/icons/next-icon.es6.jsx +18 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/input_select.es6.jsx +21 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/tables/table.es6.jsx +22 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-annotated-section.es6.jsx +29 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-empty-state.es6.jsx +35 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-footer-help.es6.jsx +13 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-layout-item.es6.jsx +11 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-layout-section.es6.jsx +19 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-layout-sections.es6.jsx +11 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-layout.es6.jsx +11 -0
- data/app/assets/javascripts/disco_app/components/ui-kit/ui-layout/ui-page-actions.es6.jsx +48 -0
- data/app/assets/javascripts/disco_app/components.js +2 -0
- data/app/assets/javascripts/disco_app/disco_app.js +9 -0
- data/app/assets/javascripts/disco_app/frame.js +152 -0
- data/app/assets/javascripts/disco_app/shopify-turbolinks.js +7 -0
- data/app/assets/javascripts/disco_app/ui-kit.js +1 -0
- data/app/assets/stylesheets/disco_app/admin/_header.scss +75 -0
- data/app/assets/stylesheets/disco_app/admin/_layout.scss +32 -0
- data/app/assets/stylesheets/disco_app/admin/_nav.scss +184 -0
- data/app/assets/stylesheets/disco_app/admin.scss +11 -0
- data/app/assets/stylesheets/disco_app/disco_app.scss +19 -0
- data/app/assets/stylesheets/disco_app/frame/_buttons.scss +54 -0
- data/app/assets/stylesheets/disco_app/frame/_forms.scss +26 -0
- data/app/assets/stylesheets/disco_app/frame/_layout.scss +77 -0
- data/app/assets/stylesheets/disco_app/frame/_type.scss +25 -0
- data/app/assets/stylesheets/disco_app/frame.scss +10 -0
- data/app/assets/stylesheets/disco_app/mixins/_flexbox.scss +400 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-empty-state.scss +121 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-footer-help.scss +28 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-icons.scss +28 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-kit.scss +5113 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-layout.scss +15 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-page-actions.scss +21 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-tabs.scss +75 -0
- data/app/assets/stylesheets/disco_app/ui-kit/_ui-type.scss +13 -0
- data/app/controllers/disco_app/admin/app_settings_controller.rb +3 -0
- data/app/controllers/disco_app/admin/application_controller.rb +3 -0
- data/app/controllers/disco_app/admin/concerns/app_settings_controller.rb +24 -0
- data/app/controllers/disco_app/admin/concerns/authenticated_controller.rb +20 -0
- data/app/controllers/disco_app/admin/concerns/plans_controller.rb +54 -0
- data/app/controllers/disco_app/admin/concerns/shops_controller.rb +7 -0
- data/app/controllers/disco_app/admin/concerns/subscriptions_controller.rb +29 -0
- data/app/controllers/disco_app/admin/plans_controller.rb +3 -0
- data/app/controllers/disco_app/admin/resources/shops_controller.rb +3 -0
- data/app/controllers/disco_app/admin/shops_controller.rb +3 -0
- data/app/controllers/disco_app/admin/subscriptions_controller.rb +3 -0
- data/app/controllers/disco_app/charges_controller.rb +47 -0
- data/app/controllers/disco_app/concerns/app_proxy_controller.rb +40 -0
- data/app/controllers/disco_app/concerns/authenticated_controller.rb +56 -0
- data/app/controllers/disco_app/concerns/carrier_request_controller.rb +21 -0
- data/app/controllers/disco_app/frame_controller.rb +9 -0
- data/app/controllers/disco_app/install_controller.rb +27 -0
- data/app/controllers/disco_app/subscriptions_controller.rb +32 -0
- data/app/controllers/disco_app/webhooks_controller.rb +46 -0
- data/app/controllers/sessions_controller.rb +28 -0
- data/app/helpers/disco_app/application_helper.rb +50 -0
- data/app/jobs/disco_app/app_installed_job.rb +3 -0
- data/app/jobs/disco_app/app_uninstalled_job.rb +3 -0
- data/app/jobs/disco_app/concerns/app_installed_job.rb +39 -0
- data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +20 -0
- data/app/jobs/disco_app/concerns/render_asset_group_job.rb +8 -0
- data/app/jobs/disco_app/concerns/shop_update_job.rb +13 -0
- data/app/jobs/disco_app/concerns/subscription_changed_job.rb +7 -0
- data/app/jobs/disco_app/concerns/synchronise_carrier_service_job.rb +52 -0
- data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +61 -0
- data/app/jobs/disco_app/render_asset_group_job.rb +3 -0
- data/app/jobs/disco_app/shop_job.rb +27 -0
- data/app/jobs/disco_app/shop_update_job.rb +3 -0
- data/app/jobs/disco_app/subscription_changed_job.rb +3 -0
- data/app/jobs/disco_app/synchronise_carrier_service_job.rb +3 -0
- data/app/jobs/disco_app/synchronise_webhooks_job.rb +3 -0
- data/app/models/disco_app/app_settings.rb +3 -0
- data/app/models/disco_app/application_charge.rb +18 -0
- data/app/models/disco_app/concerns/app_settings.rb +7 -0
- data/app/models/disco_app/concerns/plan.rb +26 -0
- data/app/models/disco_app/concerns/plan_code.rb +15 -0
- data/app/models/disco_app/concerns/renders_assets.rb +166 -0
- data/app/models/disco_app/concerns/shop.rb +63 -0
- data/app/models/disco_app/concerns/subscription.rb +60 -0
- data/app/models/disco_app/concerns/synchronises.rb +39 -0
- data/app/models/disco_app/plan.rb +3 -0
- data/app/models/disco_app/plan_code.rb +3 -0
- data/app/models/disco_app/recurring_application_charge.rb +18 -0
- data/app/models/disco_app/session_storage.rb +18 -0
- data/app/models/disco_app/shop.rb +3 -0
- data/app/models/disco_app/subscription.rb +3 -0
- data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +100 -0
- data/app/resources/disco_app/admin/resources/shop_resource.rb +4 -0
- data/app/services/disco_app/carrier_request_service.rb +15 -0
- data/app/services/disco_app/charges_service.rb +81 -0
- data/app/services/disco_app/proxy_service.rb +17 -0
- data/app/services/disco_app/subscription_service.rb +46 -0
- data/app/services/disco_app/webhook_service.rb +30 -0
- data/app/views/disco_app/admin/app_settings/edit.html.erb +5 -0
- data/app/views/disco_app/admin/plans/_form.html.erb +72 -0
- data/app/views/disco_app/admin/plans/_plan_code_fields.html.erb +15 -0
- data/app/views/disco_app/admin/plans/edit.html.erb +7 -0
- data/app/views/disco_app/admin/plans/index.html.erb +43 -0
- data/app/views/disco_app/admin/plans/new.html.erb +7 -0
- data/app/views/disco_app/admin/shops/index.html.erb +13 -0
- data/app/views/disco_app/admin/subscriptions/edit.html.erb +33 -0
- data/app/views/disco_app/charges/activate.html.erb +1 -0
- data/app/views/disco_app/charges/create.html.erb +1 -0
- data/app/views/disco_app/charges/new.html.erb +12 -0
- data/app/views/disco_app/frame/frame.html.erb +36 -0
- data/app/views/disco_app/install/installing.html.erb +7 -0
- data/app/views/disco_app/install/uninstalling.html.erb +1 -0
- data/app/views/disco_app/proxy_errors/404.html.erb +1 -0
- data/app/views/disco_app/shared/_card.html.erb +14 -0
- data/app/views/disco_app/shared/_icons.html.erb +3 -0
- data/app/views/disco_app/shared/_section.html.erb +17 -0
- data/app/views/disco_app/subscriptions/new.html.erb +25 -0
- data/app/views/layouts/admin/_nav_items.erb +20 -0
- data/app/views/layouts/admin.html.erb +67 -0
- data/app/views/layouts/application.html.erb +18 -0
- data/app/views/layouts/embedded_app.html.erb +44 -0
- data/app/views/layouts/embedded_app_modal.html.erb +28 -0
- data/app/views/sessions/new.html.erb +26 -0
- data/config/routes.rb +48 -0
- data/db/migrate/20150525000000_create_shops_if_not_existent.rb +15 -0
- data/db/migrate/20150525162112_add_status_to_shops.rb +5 -0
- data/db/migrate/20150525171422_add_meta_to_shops.rb +11 -0
- data/db/migrate/20150629210346_add_charge_status_to_shop.rb +5 -0
- data/db/migrate/20150814214025_add_more_meta_to_shops.rb +15 -0
- data/db/migrate/20151017231302_create_disco_app_plans.rb +13 -0
- data/db/migrate/20151017232027_create_disco_app_subscriptions.rb +15 -0
- data/db/migrate/20151017234409_move_shop_to_disco_app_engine.rb +5 -0
- data/db/migrate/20160112233706_create_disco_app_sessions.rb +12 -0
- data/db/migrate/20160113194418_add_shop_id_to_disco_app_sessions.rb +6 -0
- data/db/migrate/20160223111044_create_disco_app_settings.rb +8 -0
- data/db/migrate/20160301223215_update_plans.rb +22 -0
- data/db/migrate/20160301224558_update_subscriptions.rb +13 -0
- data/db/migrate/20160302104816_create_disco_app_recurring_application_charges.rb +14 -0
- data/db/migrate/20160302105259_create_disco_app_application_charges.rb +14 -0
- data/db/migrate/20160302134728_drop_charge_status_from_shops.rb +5 -0
- data/db/migrate/20160302142941_add_shopify_attributes_to_charges.rb +8 -0
- data/db/migrate/20160331093148_create_disco_app_plan_codes.rb +14 -0
- data/db/migrate/20160401044420_add_status_to_plan_codes.rb +5 -0
- data/db/migrate/20160401045551_add_amount_and_plan_code_to_disco_app_subscriptions.rb +7 -0
- data/db/migrate/20160425205211_add_source_to_disco_app_subscriptions.rb +5 -0
- data/db/migrate/20160426033520_add_trial_period_days_to_disco_app_subscriptions.rb +5 -0
- data/db/migrate/20160513140727_add_name_to_disco_app_shops.rb +5 -0
- data/db/migrate/20160521135510_move_shop_to_synchronises.rb +61 -0
- data/lib/disco_app/configuration.rb +39 -0
- data/lib/disco_app/constants.rb +4 -0
- data/lib/disco_app/engine.rb +26 -0
- data/lib/disco_app/session.rb +14 -0
- data/lib/disco_app/support/file_fixtures.rb +23 -0
- data/lib/disco_app/test_help.rb +11 -0
- data/lib/disco_app/version.rb +3 -0
- data/lib/disco_app.rb +7 -0
- data/lib/generators/disco_app/USAGE +5 -0
- data/lib/generators/disco_app/disco_app_generator.rb +235 -0
- data/lib/generators/disco_app/templates/assets/javascripts/application.js +17 -0
- data/lib/generators/disco_app/templates/assets/javascripts/components.js +3 -0
- data/lib/generators/disco_app/templates/assets/stylesheets/application.scss +5 -0
- data/lib/generators/disco_app/templates/config/database.yml.tt +20 -0
- data/lib/generators/disco_app/templates/config/newrelic.yml +26 -0
- data/lib/generators/disco_app/templates/config/puma.rb +15 -0
- data/lib/generators/disco_app/templates/controllers/home_controller.rb +7 -0
- data/lib/generators/disco_app/templates/initializers/disco_app.rb +19 -0
- data/lib/generators/disco_app/templates/initializers/rollbar.rb +12 -0
- data/lib/generators/disco_app/templates/initializers/session_store.rb +2 -0
- data/lib/generators/disco_app/templates/initializers/shopify_app.rb +7 -0
- data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +7 -0
- data/lib/generators/disco_app/templates/root/CHECKS +4 -0
- data/lib/generators/disco_app/templates/root/Procfile +2 -0
- data/lib/generators/disco_app/templates/views/home/index.html.erb +2 -0
- data/lib/tasks/carrier_service.rake +10 -0
- data/lib/tasks/database.rake +8 -0
- data/lib/tasks/sessions.rake +9 -0
- data/lib/tasks/shops.rake +10 -0
- data/lib/tasks/start.rake +3 -0
- data/lib/tasks/webhooks.rake +10 -0
- data/test/controllers/disco_app/admin/shops_controller_test.rb +54 -0
- data/test/controllers/disco_app/charges_controller_test.rb +99 -0
- data/test/controllers/disco_app/install_controller_test.rb +50 -0
- data/test/controllers/disco_app/subscriptions_controller_test.rb +68 -0
- data/test/controllers/disco_app/webhooks_controller_test.rb +58 -0
- data/test/controllers/home_controller_test.rb +92 -0
- data/test/controllers/proxy_controller_test.rb +42 -0
- data/test/disco_app_test.rb +7 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +17 -0
- data/test/dummy/app/assets/stylesheets/application.scss +5 -0
- data/test/dummy/app/controllers/application_controller.rb +6 -0
- data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +8 -0
- data/test/dummy/app/controllers/home_controller.rb +7 -0
- data/test/dummy/app/controllers/proxy_controller.rb +8 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/disco_app/app_installed_job.rb +16 -0
- data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +11 -0
- data/test/dummy/app/jobs/products_create_job.rb +7 -0
- data/test/dummy/app/jobs/products_delete_job.rb +7 -0
- data/test/dummy/app/jobs/products_update_job.rb +7 -0
- data/test/dummy/app/models/disco_app/shop.rb +15 -0
- data/test/dummy/app/models/js_configuration.rb +8 -0
- data/test/dummy/app/models/product.rb +6 -0
- data/test/dummy/app/models/widget_configuration.rb +10 -0
- data/test/dummy/app/views/assets/script_tag.js.erb +1 -0
- data/test/dummy/app/views/assets/test.js.erb +1 -0
- data/test/dummy/app/views/assets/widget.js.erb +2 -0
- data/test/dummy/app/views/assets/widget.scss.erb +3 -0
- data/test/dummy/app/views/home/index.html.erb +2 -0
- data/test/dummy/app/views/snippets/widget.liquid.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +38 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.codeship.yml +23 -0
- data/test/dummy/config/database.gitlab-ci.yml +24 -0
- data/test/dummy/config/database.yml +20 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +85 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/disco_app.rb +19 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/omniauth.rb +9 -0
- data/test/dummy/config/initializers/session_store.rb +2 -0
- data/test/dummy/config/initializers/shopify_app.rb +7 -0
- data/test/dummy/config/initializers/shopify_session_repository.rb +7 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +10 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20160307182229_create_products.rb +11 -0
- data/test/dummy/db/migrate/20160530160739_create_asset_models.rb +19 -0
- data/test/dummy/db/schema.rb +141 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/fixtures/api/widget_store/assets/create_script_tag_js_request.json +6 -0
- data/test/fixtures/api/widget_store/assets/create_script_tag_js_response.json +12 -0
- data/test/fixtures/api/widget_store/assets/create_script_tag_request.json +6 -0
- data/test/fixtures/api/widget_store/assets/create_script_tag_response.json +10 -0
- data/test/fixtures/api/widget_store/assets/create_test_js_request.json +6 -0
- data/test/fixtures/api/widget_store/assets/create_test_js_response.json +12 -0
- data/test/fixtures/api/widget_store/assets/create_widget_js_request.json +6 -0
- data/test/fixtures/api/widget_store/assets/create_widget_js_response.json +12 -0
- data/test/fixtures/api/widget_store/assets/create_widget_liquid_request.json +6 -0
- data/test/fixtures/api/widget_store/assets/create_widget_liquid_response.json +12 -0
- data/test/fixtures/api/widget_store/assets/create_widget_scss_request.json +6 -0
- data/test/fixtures/api/widget_store/assets/create_widget_scss_response.json +12 -0
- data/test/fixtures/api/widget_store/assets/get_script_tags_empty_request.json +1 -0
- data/test/fixtures/api/widget_store/assets/get_script_tags_empty_response.json +1 -0
- data/test/fixtures/api/widget_store/assets/get_script_tags_preexisting_request.json +1 -0
- data/test/fixtures/api/widget_store/assets/get_script_tags_preexisting_response.json +12 -0
- data/test/fixtures/api/widget_store/assets/update_script_tag_request.json +10 -0
- data/test/fixtures/api/widget_store/assets/update_script_tag_response.json +10 -0
- data/test/fixtures/api/widget_store/charges/activate_application_charge_request.json +16 -0
- data/test/fixtures/api/widget_store/charges/activate_application_charge_response.json +1 -0
- data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_request.json +20 -0
- data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_response.json +1 -0
- data/test/fixtures/api/widget_store/charges/create_application_charge_request.json +9 -0
- data/test/fixtures/api/widget_store/charges/create_application_charge_response.json +16 -0
- data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_request.json +9 -0
- data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_response.json +20 -0
- data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_request.json +9 -0
- data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_response.json +20 -0
- data/test/fixtures/api/widget_store/charges/get_accepted_application_charge_response.json +16 -0
- data/test/fixtures/api/widget_store/charges/get_accepted_recurring_application_charge_response.json +20 -0
- data/test/fixtures/api/widget_store/charges/get_declined_application_charge_response.json +16 -0
- data/test/fixtures/api/widget_store/charges/get_declined_recurring_application_charge_response.json +20 -0
- data/test/fixtures/api/widget_store/charges/get_pending_application_charge_response.json +16 -0
- data/test/fixtures/api/widget_store/charges/get_pending_recurring_application_charge_response.json +20 -0
- data/test/fixtures/api/widget_store/shop.json +46 -0
- data/test/fixtures/api/widget_store/webhooks.json +1 -0
- data/test/fixtures/assets/test.js +1 -0
- data/test/fixtures/assets/test.min.js +1 -0
- data/test/fixtures/disco_app/application_charges.yml +11 -0
- data/test/fixtures/disco_app/plan_codes.yml +13 -0
- data/test/fixtures/disco_app/plans.yml +37 -0
- data/test/fixtures/disco_app/recurring_application_charges.yml +11 -0
- data/test/fixtures/disco_app/shops.yml +10 -0
- data/test/fixtures/disco_app/subscriptions.yml +22 -0
- data/test/fixtures/js_configurations.yml +3 -0
- data/test/fixtures/products.yml +4 -0
- data/test/fixtures/webhooks/app_uninstalled.json +46 -0
- data/test/fixtures/webhooks/product_created.json +167 -0
- data/test/fixtures/webhooks/product_deleted.json +3 -0
- data/test/fixtures/webhooks/product_updated.json +167 -0
- data/test/fixtures/widget_configurations.yml +4 -0
- data/test/integration/synchronises_test.rb +55 -0
- data/test/jobs/disco_app/app_installed_job_test.rb +55 -0
- data/test/jobs/disco_app/app_uninstalled_job_test.rb +30 -0
- data/test/models/disco_app/plan_test.rb +5 -0
- data/test/models/disco_app/renders_assets_test.rb +109 -0
- data/test/models/disco_app/session_test.rb +31 -0
- data/test/models/disco_app/shop_test.rb +27 -0
- data/test/models/disco_app/subscription_test.rb +19 -0
- data/test/services/disco_app/charges_service_test.rb +112 -0
- data/test/services/disco_app/subscription_service_test.rb +60 -0
- data/test/support/test_file_fixtures.rb +29 -0
- data/test/support/test_shopify_api.rb +16 -0
- data/test/test_helper.rb +55 -0
- metadata +827 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class DiscoApp::RecurringApplicationCharge < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
belongs_to :shop
|
|
4
|
+
belongs_to :subscription
|
|
5
|
+
|
|
6
|
+
enum status: [:pending, :accepted, :declined, :active, :cancelled, :expired]
|
|
7
|
+
|
|
8
|
+
scope :active, -> { where status: statuses[:active] }
|
|
9
|
+
|
|
10
|
+
def recurring?
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def activate_url
|
|
15
|
+
DiscoApp::Engine.routes.url_helpers.activate_subscription_charge_url(subscription, self)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module DiscoApp
|
|
2
|
+
class SessionStorage
|
|
3
|
+
def self.store(session)
|
|
4
|
+
shop = Shop.find_or_initialize_by(shopify_domain: session.url)
|
|
5
|
+
shop.shopify_token = session.token
|
|
6
|
+
shop.save!
|
|
7
|
+
shop.id
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.retrieve(id)
|
|
11
|
+
return unless id
|
|
12
|
+
shop = Shop.find(id)
|
|
13
|
+
ShopifyAPI::Session.new(shop.shopify_domain, shop.shopify_token)
|
|
14
|
+
rescue ActiveRecord::RecordNotFound
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'jsonapi/resource'
|
|
2
|
+
|
|
3
|
+
module DiscoApp::Admin::Resources::Concerns::ShopResource
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
|
|
8
|
+
attributes :domain, :status, :created_at
|
|
9
|
+
attributes :email, :country_name, :currency, :plan_display_name
|
|
10
|
+
attributes :current_subscription_id, :current_subscription_display_amount, :current_subscription_display_plan, :current_subscription_display_plan_code, :current_subscription_source
|
|
11
|
+
attributes :installed_duration
|
|
12
|
+
|
|
13
|
+
model_name 'DiscoApp::Shop'
|
|
14
|
+
|
|
15
|
+
filters :query, :status
|
|
16
|
+
|
|
17
|
+
# Adjust the base records method to ensure only models for the authenticated domain are retrieved.
|
|
18
|
+
def self.records(options = {})
|
|
19
|
+
records = DiscoApp::Shop.order(created_at: :desc)
|
|
20
|
+
records
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Apply filters.
|
|
24
|
+
def self.apply_filter(records, filter, value, options)
|
|
25
|
+
return records if value.blank?
|
|
26
|
+
|
|
27
|
+
# Perform appropriate filtering.
|
|
28
|
+
case filter
|
|
29
|
+
when :query
|
|
30
|
+
return records.where('name LIKE ? OR shopify_domain LIKE ? OR domain LIKE ?', "%#{value.first}%", "%#{value.first}%", "%#{value.first}%")
|
|
31
|
+
when :status
|
|
32
|
+
return records.where(status: value.map { |v| DiscoApp::Shop.statuses[v.to_sym] } )
|
|
33
|
+
else
|
|
34
|
+
return super(records, filter, value)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Don't allow the update of any fields via the API.
|
|
39
|
+
def self.updatable_fields(context)
|
|
40
|
+
[]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Don't allow the creation of any fields via the API.
|
|
44
|
+
def self.creatable_fields(context)
|
|
45
|
+
[]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def email
|
|
49
|
+
@model.data['email']
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def country_name
|
|
53
|
+
@model.data['country_name']
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def currency
|
|
57
|
+
@model.data['currency']
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def plan_display_name
|
|
61
|
+
@model.data['plan_display_name']
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def current_subscription_id
|
|
65
|
+
if @model.current_subscription?
|
|
66
|
+
@model.current_subscription.id
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def current_subscription_display_amount
|
|
71
|
+
if @model.current_subscription?
|
|
72
|
+
@model.current_subscription.amount
|
|
73
|
+
else
|
|
74
|
+
'-'
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def current_subscription_display_plan
|
|
79
|
+
if @model.current_subscription?
|
|
80
|
+
@model.current_plan.name
|
|
81
|
+
else
|
|
82
|
+
'None'
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def current_subscription_display_plan_code
|
|
87
|
+
@model.current_subscription&.plan_code&.code
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def current_subscription_source
|
|
91
|
+
if @model.current_subscription?
|
|
92
|
+
@model.current_subscription.source || '-'
|
|
93
|
+
else
|
|
94
|
+
'-'
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class DiscoApp::CarrierRequestService
|
|
2
|
+
|
|
3
|
+
# Return true iff the provided hmac_to_verify matches that calculated from the
|
|
4
|
+
# given data and secret.
|
|
5
|
+
def self.is_valid_hmac?(body, secret, hmac_to_verify)
|
|
6
|
+
ActiveSupport::SecurityUtils.secure_compare(self.calculated_hmac(body, secret), hmac_to_verify.to_s)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Calculate the HMAC for the given data and secret.
|
|
10
|
+
def self.calculated_hmac(body, secret)
|
|
11
|
+
digest = OpenSSL::Digest.new('sha256')
|
|
12
|
+
Base64.encode64(OpenSSL::HMAC.digest(digest, secret, body)).strip
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
class DiscoApp::ChargesService
|
|
2
|
+
|
|
3
|
+
# Create the appropriate type of Shopify charge for the given subscription
|
|
4
|
+
# (either one-time or recurring) and return.
|
|
5
|
+
def self.create(shop, subscription)
|
|
6
|
+
# Create the charge object locally first.
|
|
7
|
+
charge = subscription.charge_class.create!(
|
|
8
|
+
shop: shop,
|
|
9
|
+
subscription: subscription,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# Create the charge object on Shopify.
|
|
13
|
+
shopify_charge = shop.temp {
|
|
14
|
+
subscription.shopify_charge_class.create(
|
|
15
|
+
name: subscription.plan.name,
|
|
16
|
+
price: '%.2f' % (subscription.amount.to_f / 100.0),
|
|
17
|
+
trial_days: subscription.plan.has_trial? ? subscription.trial_period_days : nil,
|
|
18
|
+
return_url: charge.activate_url,
|
|
19
|
+
test: !DiscoApp.configuration.real_charges?
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# If we couldn't create the charge on Shopify, return nil.
|
|
24
|
+
if shopify_charge.nil?
|
|
25
|
+
return nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Update the local record of the charge from Shopify's created charge, then
|
|
29
|
+
# return it.
|
|
30
|
+
charge.update(
|
|
31
|
+
shopify_id: shopify_charge.id,
|
|
32
|
+
confirmation_url: shopify_charge.confirmation_url
|
|
33
|
+
)
|
|
34
|
+
charge
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Attempt to activate the given Shopify charge for the given Shop using the
|
|
38
|
+
# Shopify API. Returns true on successful activation, false otherwise.
|
|
39
|
+
def self.activate(shop, charge)
|
|
40
|
+
begin
|
|
41
|
+
# Start by fetching the Shopify charge to check that it was accepted.
|
|
42
|
+
shopify_charge = shop.temp {
|
|
43
|
+
charge.subscription.shopify_charge_class.find(charge.shopify_id)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Update the status of the local charge based on the Shopify charge.
|
|
47
|
+
charge.send("#{shopify_charge.status}!") if charge.respond_to? "#{shopify_charge.status}!"
|
|
48
|
+
|
|
49
|
+
# If the charge wasn't accepted, fail and return.
|
|
50
|
+
return false unless charge.accepted?
|
|
51
|
+
|
|
52
|
+
# If the charge was indeed accepted, activate it via Shopify.
|
|
53
|
+
charge.shop.temp {
|
|
54
|
+
shopify_charge.activate
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# If the charge was recurring, make sure that all other local recurring
|
|
58
|
+
# charges are marked inactive.
|
|
59
|
+
if charge.recurring?
|
|
60
|
+
self.cancel_recurring_charges(shop, charge)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
charge.active!
|
|
64
|
+
|
|
65
|
+
true
|
|
66
|
+
rescue
|
|
67
|
+
false
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Cancel all recurring charges for the given shop. If the optional charge
|
|
72
|
+
# parameter is given, it will be excluded from the cancellation.
|
|
73
|
+
def self.cancel_recurring_charges(shop, charge = nil)
|
|
74
|
+
charges = DiscoApp::RecurringApplicationCharge.where(shop: shop)
|
|
75
|
+
if charge.present?
|
|
76
|
+
charges = charges.where.not(id: charge)
|
|
77
|
+
end
|
|
78
|
+
charges.update_all(status: DiscoApp::RecurringApplicationCharge.statuses[:cancelled])
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class DiscoApp::ProxyService
|
|
2
|
+
|
|
3
|
+
# Return true iff the signature provided in the given query string matches
|
|
4
|
+
# that calculated from the remaining query parameters and the given secret.
|
|
5
|
+
def self.proxy_signature_is_valid?(query_string, secret)
|
|
6
|
+
query_hash = Rack::Utils.parse_query(query_string)
|
|
7
|
+
signature = query_hash.delete('signature').to_s
|
|
8
|
+
ActiveSupport::SecurityUtils.variable_size_secure_compare(self.calculated_signature(query_hash, secret), signature)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Return the calculated signature for the given query hash and secret.
|
|
12
|
+
def self.calculated_signature(query_hash, secret)
|
|
13
|
+
sorted_params = query_hash.collect{ |k, v| "#{k}=#{Array(v).join(',')}" }.sort.join
|
|
14
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, sorted_params)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class DiscoApp::SubscriptionService
|
|
2
|
+
|
|
3
|
+
# Subscribe the given shop to the given plan, optionally using the given plan
|
|
4
|
+
# code and optionally tracking the subscription source.
|
|
5
|
+
def self.subscribe(shop, plan, plan_code = nil, source = nil)
|
|
6
|
+
|
|
7
|
+
# If a plan code was provided, fetch it for the given plan.
|
|
8
|
+
plan_code_instance = nil
|
|
9
|
+
if plan_code.present?
|
|
10
|
+
plan_code_instance = DiscoApp::PlanCode.available.find_by(plan: plan, code: plan_code)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Cancel any existing current subscriptions.
|
|
14
|
+
shop.subscriptions.current.update_all(
|
|
15
|
+
status: DiscoApp::Subscription.statuses[:cancelled],
|
|
16
|
+
cancelled_at: Time.now
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Get the amount that should be charged for the subscription.
|
|
20
|
+
subscription_amount = plan_code_instance.present? ? plan_code_instance.amount : plan.amount
|
|
21
|
+
|
|
22
|
+
# Get the date the subscription trial should end.
|
|
23
|
+
subscription_trial_period_days = plan_code_instance.present? ? plan_code_instance.trial_period_days : plan.trial_period_days
|
|
24
|
+
|
|
25
|
+
# Create the new subscription.
|
|
26
|
+
new_subscription = DiscoApp::Subscription.create!(
|
|
27
|
+
shop: shop,
|
|
28
|
+
plan: plan,
|
|
29
|
+
plan_code: plan_code_instance,
|
|
30
|
+
status: DiscoApp::Subscription.statuses[plan.has_trial? ? :trial : :active],
|
|
31
|
+
subscription_type: plan.plan_type,
|
|
32
|
+
amount: subscription_amount,
|
|
33
|
+
trial_period_days: plan.has_trial? ? subscription_trial_period_days : nil,
|
|
34
|
+
trial_start_at: plan.has_trial? ? Time.now : nil,
|
|
35
|
+
trial_end_at: plan.has_trial? ? subscription_trial_period_days.days.from_now : nil,
|
|
36
|
+
source: source
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Enqueue the subscription changed background job.
|
|
40
|
+
DiscoApp::SubscriptionChangedJob.perform_later(shop, new_subscription)
|
|
41
|
+
|
|
42
|
+
# Return the new subscription.
|
|
43
|
+
new_subscription
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class DiscoApp::WebhookService
|
|
2
|
+
|
|
3
|
+
# Return true iff the provided hmac_to_verify matches that calculated from the
|
|
4
|
+
# given data and secret.
|
|
5
|
+
def self.is_valid_hmac?(body, secret, hmac_to_verify)
|
|
6
|
+
ActiveSupport::SecurityUtils.secure_compare(self.calculated_hmac(body, secret), hmac_to_verify.to_s)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Calculate the HMAC for the given data and secret.
|
|
10
|
+
def self.calculated_hmac(body, secret)
|
|
11
|
+
digest = OpenSSL::Digest.new('sha256')
|
|
12
|
+
Base64.encode64(OpenSSL::HMAC.digest(digest, secret, body)).strip
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Try to find a job class for the given webhook topic.
|
|
16
|
+
def self.find_job_class(topic)
|
|
17
|
+
begin
|
|
18
|
+
# First try to find a top-level matching job class.
|
|
19
|
+
"#{topic}_job".gsub('/', '_').classify.constantize
|
|
20
|
+
rescue NameError
|
|
21
|
+
# If that fails, try to find a DiscoApp:: prefixed job class.
|
|
22
|
+
begin
|
|
23
|
+
%Q{DiscoApp::#{"#{topic}_job".gsub('/', '_').classify}}.constantize
|
|
24
|
+
rescue NameError
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<section class="section">
|
|
2
|
+
<div class="layout-content">
|
|
3
|
+
<section class="layout-content__main">
|
|
4
|
+
<div class="next-grid">
|
|
5
|
+
<div class="next-grid__cell">
|
|
6
|
+
<div class="next-card">
|
|
7
|
+
|
|
8
|
+
<header class="next-card__header">
|
|
9
|
+
<h1>Plan</h1>
|
|
10
|
+
</header>
|
|
11
|
+
|
|
12
|
+
<section class="next-card__section">
|
|
13
|
+
<div class="form-group">
|
|
14
|
+
<%= f.label(:name, 'Name') %>
|
|
15
|
+
<%= f.text_field(:name) %>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="form-group">
|
|
19
|
+
<%= f.label(:status, 'Status') %>
|
|
20
|
+
<%= f.select(:status, DiscoApp::Plan.statuses.map { |s| [s.first.humanize, s.first] }) %>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div class="form-group">
|
|
24
|
+
<%= f.label(:plan_type, 'Plan Type') %>
|
|
25
|
+
<%= f.select(:plan_type, DiscoApp::Plan.plan_types.map { |s| [s.first.humanize, s.first] }) %>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="form-group">
|
|
29
|
+
<%= f.label(:trial_period_days, 'Trial Period Days') %>
|
|
30
|
+
<%= f.number_field(:trial_period_days) %>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="form-group">
|
|
34
|
+
<%= f.label(:amount, 'Amount') %>
|
|
35
|
+
<%= f.number_field(:amount) %>
|
|
36
|
+
</div>
|
|
37
|
+
</section>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="next-grid__cell">
|
|
41
|
+
<div class="next-card next-card--aside">
|
|
42
|
+
<header class="next-card__header">
|
|
43
|
+
<h1>Plan Codes</h1>
|
|
44
|
+
</header>
|
|
45
|
+
|
|
46
|
+
<%= f.fields_for :plan_codes do |plan_code| %>
|
|
47
|
+
<%= render 'plan_code_fields', f: plan_code %>
|
|
48
|
+
<% end %>
|
|
49
|
+
|
|
50
|
+
<br>
|
|
51
|
+
|
|
52
|
+
<%= link_to_add_fields('Add New Plan Code', f, :plan_codes) %>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<hr />
|
|
57
|
+
<div class="row">
|
|
58
|
+
<div class="col-md-12">
|
|
59
|
+
<%= f.submit 'Save', { class: 'btn btn-primary' } %>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
</div>
|
|
64
|
+
</section>
|
|
65
|
+
<script type="text/javascript">
|
|
66
|
+
$('form').on('click', '.add_fields', function(event) {
|
|
67
|
+
var time = new Date().getTime();
|
|
68
|
+
var regexp = new RegExp($(this).data('id'), 'g');
|
|
69
|
+
$(this).before($(this).data('fields').replace(regexp, time));
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
});
|
|
72
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<section class="next-card__section">
|
|
2
|
+
<div class="app-container">
|
|
3
|
+
<%= f.label(:code, 'Code') %>
|
|
4
|
+
<%= f.text_field(:code) %>
|
|
5
|
+
|
|
6
|
+
<%= f.label(:trial_period_days, 'Trial Period Days') %>
|
|
7
|
+
<%= f.number_field(:trial_period_days) %>
|
|
8
|
+
|
|
9
|
+
<%= f.label(:amount, 'Amount') %>
|
|
10
|
+
<%= f.number_field(:amount) %>
|
|
11
|
+
|
|
12
|
+
<%= f.label :_destroy, 'Remove Plan' %>
|
|
13
|
+
<%= f.check_box :_destroy %>
|
|
14
|
+
</div>
|
|
15
|
+
</section>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<% provide(:title, 'Plans') %>
|
|
2
|
+
|
|
3
|
+
<div class="next-grid">
|
|
4
|
+
<div class="next-grid__cell">
|
|
5
|
+
<div class="next-card">
|
|
6
|
+
<% unless @plans.empty? %>
|
|
7
|
+
<table class="table">
|
|
8
|
+
<thead>
|
|
9
|
+
<tr>
|
|
10
|
+
<th>Name</th>
|
|
11
|
+
<th>Status</th>
|
|
12
|
+
<th>Plan Type</th>
|
|
13
|
+
<th>Trial Period</th>
|
|
14
|
+
<th>Amount</th>
|
|
15
|
+
<th>Currency</th>
|
|
16
|
+
<th>Interval</th>
|
|
17
|
+
<th>Interval Count</th>
|
|
18
|
+
<th></th>
|
|
19
|
+
</tr>
|
|
20
|
+
</thead>
|
|
21
|
+
<tbody>
|
|
22
|
+
<% @plans.each do |plan| %>
|
|
23
|
+
<tr>
|
|
24
|
+
<td><%= link_to(plan.name, edit_admin_plan_path(plan)) %></td>
|
|
25
|
+
<td><%= plan.status %></td>
|
|
26
|
+
<td><%= plan.plan_type %></td>
|
|
27
|
+
<td><%= plan.trial_period_days %></td>
|
|
28
|
+
<td><%= plan.amount %></td>
|
|
29
|
+
<td><%= plan.currency %></td>
|
|
30
|
+
<td><%= plan.interval %></td>
|
|
31
|
+
<td><%= plan.interval_count %></td>
|
|
32
|
+
<td><%= link_to 'Delete', admin_plan_path(plan), action: 'destroy', method: :delete, data: {confirm: "About to delete plan: #{plan.name}. Are you sure?"} %></td>
|
|
33
|
+
</tr>
|
|
34
|
+
<% end %>
|
|
35
|
+
</tbody>
|
|
36
|
+
</table>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
39
|
+
<hr/>
|
|
40
|
+
<%= link_to 'Create new plan', new_admin_plan_path, { class: 'btn btn-primary' } %>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<% provide(:title, 'Shops') %>
|
|
2
|
+
|
|
3
|
+
<div class="next-grid">
|
|
4
|
+
<div class="next-grid__cell">
|
|
5
|
+
|
|
6
|
+
<%= react_component('FilterableShopList', {
|
|
7
|
+
shopsUrl: admin_resources_shops_path(format: :json),
|
|
8
|
+
editShopUrl: edit_admin_shop_path(':id'),
|
|
9
|
+
editSubscriptionUrl: edit_admin_shop_subscription_path(':shop_id', ':id')
|
|
10
|
+
}) %>
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<% provide(:breadcrumb, 'Shops') %>
|
|
2
|
+
<% provide(:breadcrumb_url, admin_shops_path) %>
|
|
3
|
+
<% provide(:title, 'Edit subscription') %>
|
|
4
|
+
|
|
5
|
+
<div class="next-grid">
|
|
6
|
+
<div class="next-grid__cell">
|
|
7
|
+
|
|
8
|
+
<%= form_for(@subscription, url: admin_shop_subscription_path(@subscription.shop, @subscription)) do |f| %>
|
|
9
|
+
|
|
10
|
+
<%= f.label(:amount) %>
|
|
11
|
+
<%= f.number_field(:amount) %>
|
|
12
|
+
|
|
13
|
+
<%= f.label(:trial_period_days) %>
|
|
14
|
+
<%= f.number_field(:trial_period_days) %>
|
|
15
|
+
|
|
16
|
+
<p>
|
|
17
|
+
Note that adjusting the amount or trial days of the subscription will
|
|
18
|
+
clear any charge previously authorized by the user, and they'll be asked
|
|
19
|
+
to re-authorize the next time they open the application.
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<p>
|
|
23
|
+
If you're changing the amount of a subscription for an existing user and
|
|
24
|
+
don't want them to get another trial period, make sure to set "Trial
|
|
25
|
+
period days" to zero.
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<%= f.submit 'Save', { class: 'btn btn-primary' } %>
|
|
29
|
+
|
|
30
|
+
<% end %>
|
|
31
|
+
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
activate_charge
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
create_charge
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<% provide(:title, 'Thankyou') %>
|
|
2
|
+
|
|
3
|
+
<p>
|
|
4
|
+
Thanks for installing <%= DiscoApp.configuration.app_name %>!
|
|
5
|
+
</p>
|
|
6
|
+
<p>
|
|
7
|
+
Before we start setting things up, we need you to authorize a charge for the application.
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<%= form_tag disco_app.subscription_charges_path(@subscription), method: 'POST', target: '_parent' do %>
|
|
11
|
+
<%= submit_tag 'Okay', class: 'form-input' %>
|
|
12
|
+
<% end %>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Dev Frame</title>
|
|
5
|
+
<%= stylesheet_link_tag 'disco_app/frame', media: 'all' %>
|
|
6
|
+
<%= javascript_include_tag 'disco_app/frame' %>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<!-- Left Sidebar -->
|
|
10
|
+
<aside id="sidebar"></aside>
|
|
11
|
+
|
|
12
|
+
<!-- Header Bar -->
|
|
13
|
+
<header id="header">
|
|
14
|
+
<h1 id="header-title">
|
|
15
|
+
<img id="header-title-icon" src="<%= image_path('disco_app/icon.svg') %>" width="20" height="20" />
|
|
16
|
+
Shopify Dev Frame
|
|
17
|
+
</h1>
|
|
18
|
+
<div id="header-actions">
|
|
19
|
+
<!-- No action. -->
|
|
20
|
+
</div>
|
|
21
|
+
</header>
|
|
22
|
+
|
|
23
|
+
<!-- Content iFrame -->
|
|
24
|
+
<section id="content-wrapper">
|
|
25
|
+
<iframe id="content" src="/"></iframe>
|
|
26
|
+
</section>
|
|
27
|
+
|
|
28
|
+
<!-- Setup FrameApp. -->
|
|
29
|
+
<script type="text/javascript">
|
|
30
|
+
FrameApp.init({
|
|
31
|
+
debug: true,
|
|
32
|
+
iframe: document.getElementById('content')
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
35
|
+
</body>
|
|
36
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
uninstalling
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
404 Not Found
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<% disabled ||= false %>
|
|
2
|
+
<div class="next-card <% if disabled %>next-card--disabled<% end %>">
|
|
3
|
+
<% if content_for?(:card_header) %>
|
|
4
|
+
<header class="next-card__header">
|
|
5
|
+
<%= content_for :card_header %>
|
|
6
|
+
</header>
|
|
7
|
+
<% end %>
|
|
8
|
+
<%= content_for :card_content %>
|
|
9
|
+
<% if content_for?(:card_footer) %>
|
|
10
|
+
<footer class="next-card__footer">
|
|
11
|
+
<%= content_for :card_footer %>
|
|
12
|
+
</footer>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|