disco_app 0.12.7.pre.puma.pre.3 → 0.18.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Rakefile +1 -5
- data/app/assets/components/disco_app/forms/model-form.es6.jsx +2 -7
- data/app/assets/images/disco_app/.keep +0 -0
- data/app/assets/images/disco_app/logo.png +0 -0
- data/app/assets/javascripts/disco_app/components/custom/shop_row.js.jsx +2 -1
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_form.es6.jsx +16 -44
- data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-checkbox.es6.jsx +10 -5
- data/app/clients/disco_app/api_client.rb +25 -19
- data/app/clients/disco_app/graphql_client.rb +85 -0
- data/app/controllers/disco_app/admin/app_settings_controller.rb +2 -0
- data/app/controllers/disco_app/admin/application_controller.rb +3 -1
- data/app/controllers/disco_app/admin/concerns/app_settings_controller.rb +2 -1
- data/app/controllers/disco_app/admin/concerns/authenticated_controller.rb +5 -3
- data/app/controllers/disco_app/admin/concerns/plans_controller.rb +3 -2
- data/app/controllers/disco_app/admin/concerns/shops_controller.rb +1 -0
- data/app/controllers/disco_app/admin/concerns/sources_controller.rb +52 -0
- data/app/controllers/disco_app/admin/concerns/subscriptions_controller.rb +3 -2
- data/app/controllers/disco_app/admin/plans_controller.rb +2 -0
- data/app/controllers/disco_app/admin/resources/shops_controller.rb +2 -0
- data/app/controllers/disco_app/admin/shops_controller.rb +2 -0
- data/app/controllers/disco_app/admin/sources_controller.rb +5 -0
- data/app/controllers/disco_app/admin/subscriptions_controller.rb +2 -0
- data/app/controllers/disco_app/charges_controller.rb +12 -8
- data/app/controllers/disco_app/concerns/app_proxy_controller.rb +6 -6
- data/app/controllers/disco_app/concerns/authenticated_controller.rb +31 -23
- data/app/controllers/disco_app/concerns/carrier_request_controller.rb +22 -11
- data/app/controllers/disco_app/concerns/user_authenticated_controller.rb +18 -0
- data/app/controllers/disco_app/concerns/webhooks_controller.rb +49 -0
- data/app/controllers/disco_app/flow/actions_controller.rb +9 -0
- data/app/controllers/disco_app/flow/concerns/actions_controller.rb +23 -0
- data/app/controllers/disco_app/flow/concerns/trigger_usage_controller.rb +29 -0
- data/app/controllers/disco_app/flow/concerns/verifies_flow_payload.rb +39 -0
- data/app/controllers/disco_app/flow/trigger_usage_controller.rb +9 -0
- data/app/controllers/disco_app/frame_controller.rb +0 -1
- data/app/controllers/disco_app/install_controller.rb +3 -6
- data/app/controllers/disco_app/subscriptions_controller.rb +12 -4
- data/app/controllers/disco_app/user_sessions_controller.rb +58 -0
- data/app/controllers/disco_app/webhooks_controller.rb +2 -43
- data/app/controllers/sessions_controller.rb +5 -6
- data/app/helpers/disco_app/application_helper.rb +7 -7
- data/app/jobs/application_job.rb +2 -0
- data/app/jobs/disco_app/app_installed_job.rb +2 -0
- data/app/jobs/disco_app/app_uninstalled_job.rb +2 -0
- data/app/jobs/disco_app/concerns/app_installed_job.rb +3 -4
- data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +2 -1
- data/app/jobs/disco_app/concerns/customers_data_request_job.rb +13 -0
- data/app/jobs/disco_app/concerns/customers_redact_job.rb +13 -0
- data/app/jobs/disco_app/concerns/render_asset_group_job.rb +2 -1
- data/app/jobs/disco_app/concerns/shop_redact_job.rb +13 -0
- data/app/jobs/disco_app/concerns/shop_update_job.rb +10 -3
- data/app/jobs/disco_app/concerns/subscription_changed_job.rb +2 -1
- data/app/jobs/disco_app/concerns/synchronise_carrier_service_job.rb +9 -8
- data/app/jobs/disco_app/concerns/synchronise_resources_job.rb +3 -6
- data/app/jobs/disco_app/concerns/synchronise_users_job.rb +18 -0
- data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +48 -18
- data/app/jobs/disco_app/customers_data_request_job.rb +5 -0
- data/app/jobs/disco_app/customers_redact_job.rb +5 -0
- data/app/jobs/disco_app/flow/process_action_job.rb +11 -0
- data/app/jobs/disco_app/flow/process_trigger_job.rb +11 -0
- data/app/jobs/disco_app/render_asset_group_job.rb +2 -0
- data/app/jobs/disco_app/send_subscription_job.rb +1 -1
- data/app/jobs/disco_app/shop_job.rb +12 -5
- data/app/jobs/disco_app/shop_redact_job.rb +5 -0
- data/app/jobs/disco_app/shop_update_job.rb +2 -0
- data/app/jobs/disco_app/subscription_changed_job.rb +2 -0
- data/app/jobs/disco_app/synchronise_carrier_service_job.rb +2 -0
- data/app/jobs/disco_app/synchronise_resources_job.rb +2 -0
- data/app/jobs/disco_app/synchronise_users_job.rb +5 -0
- data/app/jobs/disco_app/synchronise_webhooks_job.rb +2 -0
- data/app/models/application_record.rb +5 -0
- data/app/models/disco_app/app_settings.rb +3 -1
- data/app/models/disco_app/application_charge.rb +8 -2
- data/app/models/disco_app/concerns/app_settings.rb +2 -0
- data/app/models/disco_app/concerns/can_be_liquified.rb +34 -18
- data/app/models/disco_app/concerns/has_metafields.rb +100 -44
- data/app/models/disco_app/concerns/plan.rb +15 -7
- data/app/models/disco_app/concerns/plan_code.rb +5 -3
- data/app/models/disco_app/concerns/renders_assets.rb +15 -21
- data/app/models/disco_app/concerns/shop.rb +39 -16
- data/app/models/disco_app/concerns/source.rb +13 -0
- data/app/models/disco_app/concerns/subscription.rb +14 -7
- data/app/models/disco_app/concerns/synchronises.rb +16 -16
- data/app/models/disco_app/concerns/taggable.rb +8 -3
- data/app/models/disco_app/concerns/user.rb +21 -0
- data/app/models/disco_app/flow/action.rb +9 -0
- data/app/models/disco_app/flow/concerns/action.rb +27 -0
- data/app/models/disco_app/flow/concerns/trigger.rb +28 -0
- data/app/models/disco_app/flow/concerns/trigger_usage.rb +17 -0
- data/app/models/disco_app/flow/trigger.rb +9 -0
- data/app/models/disco_app/flow/trigger_usage.rb +9 -0
- data/app/models/disco_app/plan.rb +3 -1
- data/app/models/disco_app/plan_code.rb +3 -1
- data/app/models/disco_app/recurring_application_charge.rb +9 -2
- data/app/models/disco_app/session_storage.rb +5 -2
- data/app/models/disco_app/shop.rb +3 -1
- data/app/models/disco_app/source.rb +5 -0
- data/app/models/disco_app/subscription.rb +3 -1
- data/app/models/disco_app/user.rb +5 -0
- data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +16 -19
- data/app/resources/disco_app/admin/resources/shop_resource.rb +1 -0
- data/app/services/disco_app/carrier_request_service.rb +3 -3
- data/app/services/disco_app/charges_service.rb +28 -38
- data/app/services/disco_app/flow/create_action.rb +35 -0
- data/app/services/disco_app/flow/create_trigger.rb +34 -0
- data/app/services/disco_app/flow/process_action.rb +50 -0
- data/app/services/disco_app/flow/process_trigger.rb +72 -0
- data/app/services/disco_app/flow/update_trigger_usage.rb +42 -0
- data/app/services/disco_app/partner_app_service.rb +151 -0
- data/app/services/disco_app/proxy_service.rb +2 -2
- data/app/services/disco_app/request_validation_service.rb +2 -2
- data/app/services/disco_app/subscription_service.rb +62 -28
- data/app/services/disco_app/synchronise_resources_service.rb +54 -0
- data/app/services/disco_app/webhook_service.rb +9 -11
- data/app/views/disco_app/admin/sources/_form.html.erb +34 -0
- data/app/views/disco_app/admin/sources/edit.html.erb +7 -0
- data/app/views/disco_app/admin/sources/index.html.erb +32 -0
- data/app/views/disco_app/admin/sources/new.html.erb +7 -0
- data/app/views/disco_app/user_sessions/new.html.erb +12 -0
- data/app/views/layouts/admin/_nav_items.erb +7 -0
- data/app/views/layouts/admin.html.erb +1 -2
- data/app/views/layouts/application.html.erb +1 -2
- data/app/views/layouts/embedded_app.html.erb +2 -4
- data/app/views/layouts/embedded_app_modal.html.erb +2 -3
- data/app/views/shopify_app/sessions/new.html.erb +2 -4
- data/config/routes.rb +15 -3
- data/db/migrate/20150525000000_create_shops_if_not_existent.rb +81 -81
- data/db/migrate/20170315062548_create_disco_app_sources.rb +12 -0
- data/db/migrate/20170315062629_add_sources_to_shop_subscriptions.rb +16 -0
- data/db/migrate/20170327214540_create_disco_app_users.rb +14 -0
- data/db/migrate/20170606160751_fix_disco_app_users_index.rb +8 -0
- data/db/migrate/20181229100327_create_flow_actions_and_triggers.rb +32 -0
- data/db/migrate/20200405000000_create_flow_trigger_usages.rb +16 -0
- data/lib/disco_app/configuration.rb +12 -5
- data/lib/disco_app/constants.rb +4 -2
- data/lib/disco_app/engine.rb +1 -1
- data/lib/disco_app/session.rb +1 -0
- data/lib/disco_app/support/file_fixtures.rb +2 -1
- data/lib/disco_app/version.rb +3 -1
- data/lib/generators/disco_app/install/USAGE +5 -0
- data/lib/generators/disco_app/install/install_generator.rb +297 -0
- data/lib/generators/disco_app/{templates → install/templates}/assets/javascripts/application.js +0 -0
- data/lib/generators/disco_app/{templates → install/templates}/assets/javascripts/components.js +0 -0
- data/lib/generators/disco_app/{templates → install/templates}/assets/stylesheets/application.scss +0 -0
- data/lib/generators/disco_app/install/templates/config/appsignal.yml +12 -0
- data/lib/generators/disco_app/install/templates/config/cable.yml.tt +11 -0
- data/lib/generators/disco_app/{templates → install/templates}/config/database.yml.tt +7 -3
- data/lib/generators/disco_app/install/templates/config/environments/staging.rb +108 -0
- data/lib/generators/disco_app/{templates → install/templates}/config/puma.rb +0 -0
- data/lib/generators/disco_app/{templates → install/templates}/controllers/home_controller.rb +1 -0
- data/lib/generators/disco_app/{templates → install/templates}/initializers/disco_app.rb +5 -0
- data/lib/generators/disco_app/install/templates/initializers/session_store.rb +2 -0
- data/lib/generators/disco_app/install/templates/initializers/shopify_app.rb +11 -0
- data/lib/generators/disco_app/{templates → install/templates}/initializers/shopify_session_repository.rb +2 -1
- data/lib/generators/disco_app/install/templates/initializers/timber.rb +4 -0
- data/lib/generators/disco_app/install/templates/root/.editorconfig +9 -0
- data/lib/generators/disco_app/install/templates/root/.env +27 -0
- data/lib/generators/disco_app/install/templates/root/.env.local +29 -0
- data/lib/generators/disco_app/install/templates/root/.github/PULL_REQUEST_TEMPLATE.md +18 -0
- data/lib/generators/disco_app/install/templates/root/.gitignore +65 -0
- data/lib/generators/disco_app/install/templates/root/.rspec +1 -0
- data/lib/generators/disco_app/install/templates/root/.rubocop.yml +758 -0
- data/lib/generators/disco_app/install/templates/root/.tool-versions +2 -0
- data/lib/generators/disco_app/{templates → install/templates}/root/CHECKS +0 -0
- data/lib/generators/disco_app/{templates → install/templates}/root/Procfile +0 -0
- data/lib/generators/disco_app/install/templates/root/README.md +26 -0
- data/lib/generators/disco_app/install/templates/root/package.json.tt +17 -0
- data/lib/generators/disco_app/install/templates/spec/rails_helper.rb +40 -0
- data/lib/generators/disco_app/install/templates/spec/spec_helper.rb +24 -0
- data/lib/generators/disco_app/install/templates/spec/support/active_job.rb +13 -0
- data/lib/generators/disco_app/install/templates/spec/support/coveralls.rb +3 -0
- data/lib/generators/disco_app/install/templates/spec/support/database_cleaner.rb +17 -0
- data/lib/generators/disco_app/install/templates/spec/support/factory_bot.rb +3 -0
- data/lib/generators/disco_app/install/templates/spec/support/helpers/json_helper.rb +13 -0
- data/lib/generators/disco_app/install/templates/spec/support/shared_examples/a_synchronise_job.rb +12 -0
- data/lib/generators/disco_app/install/templates/spec/support/shoulda.rb +6 -0
- data/lib/generators/disco_app/install/templates/spec/support/vcr.rb +14 -0
- data/lib/generators/disco_app/install/templates/spec/support/webmock.rb +8 -0
- data/lib/generators/disco_app/{templates → install/templates}/views/home/index.html.erb +0 -0
- data/lib/generators/disco_app/react/USAGE +5 -0
- data/lib/generators/disco_app/react/react_generator.rb +108 -0
- data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/base_controller.rb +18 -0
- data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/home_controller.rb +10 -0
- data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/shops_controller.rb +11 -0
- data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/users_controller.rb +11 -0
- data/lib/generators/disco_app/react/templates/app/controllers/embedded/home_controller.rb +13 -0
- data/lib/generators/disco_app/react/templates/app/models/api_response.rb +107 -0
- data/lib/generators/disco_app/react/templates/app/serializers/disco_app/shop_serializer.rb +13 -0
- data/lib/generators/disco_app/react/templates/app/serializers/disco_app/user_serializer.rb +13 -0
- data/lib/generators/disco_app/react/templates/app/serializers/empty_serializer.rb +5 -0
- data/lib/generators/disco_app/react/templates/app/serializers/error_serializer.rb +76 -0
- data/lib/generators/disco_app/react/templates/app/views/embedded/home/index.html.erb +12 -0
- data/lib/generators/disco_app/react/templates/app/views/layouts/embedded.html.erb +10 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/App.jsx +77 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/HomePage.jsx +34 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/EmbeddedPage.jsx +70 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/ErrorBanner.jsx +58 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/PaginationWrapper.jsx +10 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/ScrollToTop.jsx +23 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/withApi.jsx +125 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/index.jsx +39 -0
- data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/utils.js +19 -0
- data/lib/generators/disco_app/react/templates/app/webpack/packs/embedded.js +2 -0
- data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/banners.scss +7 -0
- data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/busy.scss +3 -0
- data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/index.scss +3 -0
- data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/pagination.scss +5 -0
- data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded.scss +2 -0
- data/lib/generators/disco_app/react/templates/config/initializers/mime_types.rb +13 -0
- data/lib/generators/disco_app/react/templates/config/initializers/omniauth.rb +27 -0
- data/lib/generators/disco_app/react/templates/config/initializers/version.rb.tt +7 -0
- data/lib/generators/disco_app/react/templates/config/webpack/staging.js +5 -0
- data/lib/generators/disco_app/react/templates/config/webpack/test.js +5 -0
- data/lib/generators/disco_app/react/templates/config/webpacker.yml +96 -0
- data/lib/generators/disco_app/react/templates/root/.eslintignore +5 -0
- data/lib/generators/disco_app/react/templates/root/.eslintrc +69 -0
- data/lib/generators/disco_app/react/templates/root/.prettierrc +3 -0
- data/lib/generators/disco_app/react/templates/root/VERSION +1 -0
- data/lib/generators/disco_app/react/templates/root/babel.config.js +72 -0
- data/lib/generators/disco_app/react/templates/root/package.json.tt +84 -0
- data/lib/generators/disco_app/react/templates/root/postcss.config.js +14 -0
- data/lib/tasks/api.rake +0 -2
- data/lib/tasks/carrier_service.rake +0 -2
- data/lib/tasks/database.rake +1 -1
- data/lib/tasks/partner_app.rake +26 -0
- data/lib/tasks/sessions.rake +0 -2
- data/lib/tasks/shops.rake +0 -2
- data/lib/tasks/users.rake +8 -0
- data/lib/tasks/webhooks.rake +0 -2
- data/test/clients/disco_app/api_client_test.rb +3 -3
- data/test/controllers/disco_app/admin/shops_controller_test.rb +1 -0
- data/test/controllers/disco_app/charges_controller_test.rb +19 -21
- data/test/controllers/disco_app/flow/trigger_usage_controller_test.rb +41 -0
- data/test/controllers/disco_app/install_controller_test.rb +2 -1
- data/test/controllers/disco_app/subscriptions_controller_test.rb +6 -5
- data/test/controllers/disco_app/webhooks_controller_test.rb +6 -5
- data/test/controllers/home_controller_test.rb +2 -2
- data/test/controllers/proxy_controller_test.rb +3 -3
- data/test/disco_app_test.rb +3 -1
- data/test/dummy/Rakefile +1 -1
- data/test/dummy/app/assets/config/manifest.js +2 -0
- data/test/dummy/app/controllers/application_controller.rb +2 -0
- data/test/dummy/app/controllers/carrier_request_controller.rb +1 -0
- data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +2 -1
- data/test/dummy/app/controllers/home_controller.rb +1 -0
- data/test/dummy/app/controllers/proxy_controller.rb +2 -1
- data/test/dummy/app/javascript/packs/application.js +18 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/jobs/carts_update_job.rb +1 -1
- data/test/dummy/app/jobs/disco_app/app_installed_job.rb +2 -3
- data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +3 -2
- data/test/dummy/app/jobs/products_create_job.rb +1 -1
- data/test/dummy/app/jobs/products_delete_job.rb +1 -1
- data/test/dummy/app/jobs/products_update_job.rb +1 -1
- data/test/dummy/app/models/application_record.rb +5 -0
- data/test/dummy/app/models/cart.rb +8 -7
- data/test/dummy/app/models/disco_app/shop.rb +8 -6
- data/test/dummy/app/models/js_configuration.rb +2 -1
- data/test/dummy/app/models/product.rb +4 -3
- data/test/dummy/app/models/widget_configuration.rb +2 -1
- data/test/dummy/babel.config.js +72 -0
- data/test/dummy/bin/bundle +1 -1
- data/test/dummy/bin/rails +1 -1
- data/test/dummy/bin/setup +8 -8
- data/test/dummy/bin/webpack +19 -0
- data/test/dummy/bin/webpack-dev-server +19 -0
- data/test/dummy/config/application.rb +3 -5
- data/test/dummy/config/boot.rb +2 -2
- data/test/dummy/config/database.yml +4 -0
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/staging.rb +85 -0
- data/test/dummy/config/environments/test.rb +2 -2
- data/test/dummy/config/initializers/disco_app.rb +8 -1
- data/test/dummy/config/initializers/omniauth.rb +3 -4
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/initializers/shopify_app.rb +1 -0
- data/test/dummy/config/initializers/shopify_session_repository.rb +1 -1
- data/test/dummy/config/routes.rb +0 -2
- data/test/dummy/config/secrets.yml +3 -0
- data/test/dummy/config/webpack/development.js +5 -0
- data/test/dummy/config/webpack/environment.js +3 -0
- data/test/dummy/config/webpack/production.js +5 -0
- data/test/dummy/config/webpack/test.js +5 -0
- data/test/dummy/config/webpacker.yml +95 -0
- data/test/dummy/db/migrate/20160307182229_create_products.rb +3 -1
- data/test/dummy/db/migrate/20160530160739_create_asset_models.rb +3 -1
- data/test/dummy/db/migrate/20161105054746_create_carts.rb +3 -1
- data/test/dummy/db/schema.rb +141 -88
- data/test/dummy/package.json +10 -0
- data/test/dummy/postcss.config.js +12 -0
- data/test/dummy/yarn.lock +7278 -0
- data/test/fixtures/api/subscriptions/valid_request.json +2 -2
- data/test/fixtures/api/widget_store/charges/{activate_application_charge_request.json → get_active_application_charge_response.json} +1 -1
- data/test/fixtures/api/widget_store/charges/{activate_recurring_application_charge_request.json → get_active_recurring_application_charge_response.json} +2 -2
- data/test/fixtures/api/widget_store/empty_webhooks.json +3 -0
- data/test/fixtures/api/widget_store/existing_webhooks.json +43 -0
- data/test/fixtures/api/widget_store/products/get_metafields_empty_response.json +3 -0
- data/test/fixtures/api/widget_store/products/get_metafields_with_existing_response.json +11 -0
- data/test/fixtures/api/widget_store/products/write_metafields_multiple_namespaces_request.json +4 -0
- data/test/fixtures/api/widget_store/products/write_metafields_single_namespace_request.json +2 -0
- data/test/fixtures/api/widget_store/products/write_metafields_with_existing_single_namespace_request.json +21 -0
- data/test/fixtures/api/widget_store/{charges/activate_application_charge_response.json → products/write_metafields_with_existing_single_namespace_response.json} +0 -0
- data/test/fixtures/api/widget_store/shops/get_metafields_with_existing_response.json +11 -0
- data/test/fixtures/api/widget_store/shops/write_metafields_with_existing_first_request.json +9 -0
- data/test/fixtures/api/widget_store/{charges/activate_recurring_application_charge_response.json → shops/write_metafields_with_existing_first_response.json} +0 -0
- data/test/fixtures/api/widget_store/shops/write_metafields_with_existing_second_request.json +9 -0
- data/test/fixtures/api/widget_store/shops/write_metafields_with_existing_second_response.json +1 -0
- data/test/fixtures/api/widget_store/users.json +42 -0
- data/test/fixtures/disco_app/shops.yml +9 -2
- data/test/fixtures/disco_app/sources.yml +3 -0
- data/test/fixtures/liquid/model.liquid +8 -8
- data/test/fixtures/webhooks/flow/trigger_usage.json +7 -0
- data/test/integration/synchronises_test.rb +20 -13
- data/test/jobs/disco_app/app_installed_job_test.rb +30 -11
- data/test/jobs/disco_app/app_uninstalled_job_test.rb +5 -2
- data/test/jobs/disco_app/send_subscription_job_test.rb +3 -2
- data/test/jobs/disco_app/synchronise_carrier_service_job_test.rb +1 -0
- data/test/jobs/disco_app/synchronise_users_job_test.rb +27 -0
- data/test/jobs/disco_app/synchronise_webhooks_job_test.rb +78 -9
- data/test/models/disco_app/can_be_liquified_test.rb +3 -1
- data/test/models/disco_app/has_metafields_test.rb +109 -20
- data/test/models/disco_app/renders_assets_test.rb +2 -1
- data/test/models/disco_app/session_test.rb +2 -2
- data/test/models/disco_app/shop_test.rb +1 -1
- data/test/services/disco_app/charges_service_test.rb +10 -14
- data/test/services/disco_app/flow/create_action_test.rb +51 -0
- data/test/services/disco_app/flow/create_trigger_test.rb +56 -0
- data/test/services/disco_app/flow/process_action_test.rb +68 -0
- data/test/services/disco_app/flow/process_trigger_test.rb +94 -0
- data/test/services/disco_app/flow/update_trigger_usage_test.rb +87 -0
- data/test/services/disco_app/subscription_service_test.rb +3 -2
- data/test/services/disco_app/synchronise_resources_service_test.rb +57 -0
- data/test/support/test_file_fixtures.rb +2 -2
- data/test/support/test_shopify_api.rb +1 -1
- data/test/test_helper.rb +24 -6
- data/test/vcr/flow_trigger_invalid_title.yml +35 -0
- data/test/vcr/flow_trigger_valid.yml +38 -0
- data/test/vcr/synchronise_products.yml +130 -0
- data/test/vcr/synchronise_products_paginated.yml +119 -0
- data/test/vcr/synchronise_products_since_id.yml +125 -0
- data/test/vcr/synchronise_products_with_params.yml +130 -0
- data/test/vcr/webhook_failure.yml +640 -0
- metadata +388 -142
- data/app/clients/disco_app/disco_api_error.rb +0 -2
- data/lib/generators/disco_app/USAGE +0 -5
- data/lib/generators/disco_app/disco_app_generator.rb +0 -236
- data/lib/generators/disco_app/templates/config/newrelic.yml +0 -26
- data/lib/generators/disco_app/templates/initializers/rollbar.rb +0 -23
- data/lib/generators/disco_app/templates/initializers/session_store.rb +0 -2
- data/lib/generators/disco_app/templates/initializers/shopify_app.rb +0 -6
- data/test/dummy/config/database.gitlab-ci.yml +0 -24
- data/test/fixtures/api/widget_store/charges/get_accepted_application_charge_response.json +0 -16
- data/test/fixtures/api/widget_store/charges/get_accepted_recurring_application_charge_response.json +0 -20
- data/test/fixtures/api/widget_store/webhooks.json +0 -1
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'jsonapi/resource'
|
2
2
|
|
3
3
|
module DiscoApp::Admin::Resources::Concerns::ShopResource
|
4
|
+
|
4
5
|
extend ActiveSupport::Concern
|
5
6
|
|
6
7
|
included do
|
7
|
-
|
8
8
|
attributes :domain, :status, :created_at
|
9
9
|
attributes :email, :country_name, :currency, :plan_display_name
|
10
10
|
attributes :current_subscription_id, :current_subscription_display_amount, :current_subscription_display_plan, :current_subscription_display_plan_code, :current_subscription_source
|
@@ -15,56 +15,54 @@ module DiscoApp::Admin::Resources::Concerns::ShopResource
|
|
15
15
|
filters :query, :status
|
16
16
|
|
17
17
|
# Adjust the base records method to ensure only models for the authenticated domain are retrieved.
|
18
|
-
def self.records(
|
18
|
+
def self.records(_options = {})
|
19
19
|
records = DiscoApp::Shop.order(created_at: :desc)
|
20
20
|
records
|
21
21
|
end
|
22
22
|
|
23
23
|
# Apply filters.
|
24
|
-
def self.apply_filter(records, filter, value,
|
24
|
+
def self.apply_filter(records, filter, value, _options)
|
25
25
|
return records if value.blank?
|
26
26
|
|
27
27
|
# Perform appropriate filtering.
|
28
28
|
case filter
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
# Don't allow the update of any fields via the API.
|
39
|
-
def self.updatable_fields(
|
39
|
+
def self.updatable_fields(_context)
|
40
40
|
[]
|
41
41
|
end
|
42
42
|
|
43
43
|
# Don't allow the creation of any fields via the API.
|
44
|
-
def self.creatable_fields(
|
44
|
+
def self.creatable_fields(_context)
|
45
45
|
[]
|
46
46
|
end
|
47
47
|
|
48
48
|
def email
|
49
|
-
@model.data[
|
49
|
+
@model.data[:email]
|
50
50
|
end
|
51
51
|
|
52
52
|
def country_name
|
53
|
-
@model.data[
|
53
|
+
@model.data[:country_name]
|
54
54
|
end
|
55
55
|
|
56
56
|
def currency
|
57
|
-
@model.data[
|
57
|
+
@model.data[:currency]
|
58
58
|
end
|
59
59
|
|
60
60
|
def plan_display_name
|
61
|
-
@model.data[
|
61
|
+
@model.data[:plan_display_name]
|
62
62
|
end
|
63
63
|
|
64
64
|
def current_subscription_id
|
65
|
-
if @model.current_subscription?
|
66
|
-
@model.current_subscription.id
|
67
|
-
end
|
65
|
+
@model.current_subscription.id if @model.current_subscription?
|
68
66
|
end
|
69
67
|
|
70
68
|
def current_subscription_display_amount
|
@@ -94,7 +92,6 @@ module DiscoApp::Admin::Resources::Concerns::ShopResource
|
|
94
92
|
'-'
|
95
93
|
end
|
96
94
|
end
|
97
|
-
|
98
95
|
end
|
99
96
|
|
100
97
|
end
|
@@ -2,13 +2,13 @@ class DiscoApp::CarrierRequestService
|
|
2
2
|
|
3
3
|
# Return true iff the provided hmac_to_verify matches that calculated from the
|
4
4
|
# given data and secret.
|
5
|
-
def self.
|
6
|
-
ActiveSupport::SecurityUtils.secure_compare(
|
5
|
+
def self.valid_hmac?(body, secret, hmac_to_verify)
|
6
|
+
ActiveSupport::SecurityUtils.secure_compare(calculated_hmac(body, secret), hmac_to_verify.to_s)
|
7
7
|
end
|
8
8
|
|
9
9
|
# Calculate the HMAC for the given data and secret.
|
10
10
|
def self.calculated_hmac(body, secret)
|
11
|
-
digest
|
11
|
+
digest = OpenSSL::Digest.new('sha256')
|
12
12
|
Base64.encode64(OpenSSL::HMAC.digest(digest, secret, body)).strip
|
13
13
|
end
|
14
14
|
|
@@ -6,24 +6,22 @@ class DiscoApp::ChargesService
|
|
6
6
|
# Create the charge object locally first.
|
7
7
|
charge = subscription.charge_class.create!(
|
8
8
|
shop: shop,
|
9
|
-
subscription: subscription
|
9
|
+
subscription: subscription
|
10
10
|
)
|
11
11
|
|
12
12
|
# Create the charge object on Shopify.
|
13
|
-
shopify_charge = shop.with_api_context
|
13
|
+
shopify_charge = shop.with_api_context do
|
14
14
|
subscription.shopify_charge_class.create(
|
15
15
|
name: subscription.plan.name,
|
16
|
-
price: '%.2f'
|
16
|
+
price: format('%.2f', (subscription.amount.to_f / 100.0)),
|
17
17
|
trial_days: subscription.plan.has_trial? ? subscription.trial_period_days : nil,
|
18
18
|
return_url: charge.activate_url,
|
19
19
|
test: !DiscoApp.configuration.real_charges?
|
20
20
|
)
|
21
|
-
|
21
|
+
end
|
22
22
|
|
23
23
|
# If we couldn't create the charge on Shopify, return nil.
|
24
|
-
if shopify_charge.nil?
|
25
|
-
return nil
|
26
|
-
end
|
24
|
+
return nil if shopify_charge.nil?
|
27
25
|
|
28
26
|
# Update the local record of the charge from Shopify's created charge, then
|
29
27
|
# return it.
|
@@ -34,48 +32,40 @@ class DiscoApp::ChargesService
|
|
34
32
|
charge
|
35
33
|
end
|
36
34
|
|
37
|
-
#
|
38
|
-
#
|
35
|
+
# Synchronises the status of a given charge from the Shopify API and returns
|
36
|
+
# true if it's active (and false otherwise).
|
37
|
+
#
|
38
|
+
# Previously, the activation of a charge also required updating Shopify via the
|
39
|
+
# API, but that requirement has been removed.
|
40
|
+
#
|
41
|
+
# See https://shopify.dev/changelog/auto-activation-of-charges-and-subscriptions
|
39
42
|
def self.activate(shop, charge)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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?
|
43
|
+
# Start by fetching the Shopify charge to check that it was accepted.
|
44
|
+
shopify_charge = shop.with_api_context do
|
45
|
+
charge.subscription.shopify_charge_class.find(charge.shopify_id)
|
46
|
+
end
|
51
47
|
|
52
|
-
|
53
|
-
|
54
|
-
shopify_charge.activate
|
55
|
-
}
|
48
|
+
# Update the status of the local charge based on the Shopify charge.
|
49
|
+
charge.send("#{shopify_charge.status}!") if charge.respond_to? "#{shopify_charge.status}!"
|
56
50
|
|
57
|
-
|
58
|
-
|
59
|
-
if charge.recurring?
|
60
|
-
self.cancel_recurring_charges(shop, charge)
|
61
|
-
end
|
51
|
+
# If the charge isn't active, fail and return.
|
52
|
+
return false unless charge.active?
|
62
53
|
|
63
|
-
|
54
|
+
# If the charge was recurring, make sure that all other local recurring
|
55
|
+
# charges are marked inactive.
|
56
|
+
cancel_recurring_charges(shop, charge) if charge.recurring?
|
64
57
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
58
|
+
true
|
59
|
+
rescue StandardError
|
60
|
+
false
|
69
61
|
end
|
70
62
|
|
71
63
|
# Cancel all recurring charges for the given shop. If the optional charge
|
72
64
|
# parameter is given, it will be excluded from the cancellation.
|
73
65
|
def self.cancel_recurring_charges(shop, charge = nil)
|
74
66
|
charges = DiscoApp::RecurringApplicationCharge.where(shop: shop)
|
75
|
-
if charge.present?
|
76
|
-
|
77
|
-
end
|
78
|
-
charges.update_all(status: DiscoApp::RecurringApplicationCharge.statuses[:cancelled])
|
67
|
+
charges = charges.where.not(id: charge) if charge.present?
|
68
|
+
charges.update_all(status: DiscoApp::RecurringApplicationCharge.statuses[:cancelled]) # rubocop:disable Rails/SkipsModelValidations
|
79
69
|
end
|
80
70
|
|
81
71
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'interactor'
|
2
|
+
|
3
|
+
module DiscoApp
|
4
|
+
module Flow
|
5
|
+
class CreateAction
|
6
|
+
|
7
|
+
include Interactor
|
8
|
+
|
9
|
+
delegate :shop, :action_id, :action_run_id, :properties, to: :context
|
10
|
+
delegate :action, to: :context
|
11
|
+
|
12
|
+
def call
|
13
|
+
create_action
|
14
|
+
enqueue_process_action_job
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def create_action
|
20
|
+
context.action = shop.flow_actions.create!(
|
21
|
+
action_id: action_id,
|
22
|
+
action_run_id: action_run_id,
|
23
|
+
properties: properties
|
24
|
+
)
|
25
|
+
rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation
|
26
|
+
context.fail!
|
27
|
+
end
|
28
|
+
|
29
|
+
def enqueue_process_action_job
|
30
|
+
ProcessActionJob.perform_later(shop, action)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'interactor'
|
2
|
+
|
3
|
+
module DiscoApp
|
4
|
+
module Flow
|
5
|
+
class CreateTrigger
|
6
|
+
|
7
|
+
include Interactor
|
8
|
+
|
9
|
+
delegate :shop, :title, :resource_name, :resource_url, :properties, to: :context
|
10
|
+
delegate :trigger, to: :context
|
11
|
+
|
12
|
+
def call
|
13
|
+
create_trigger
|
14
|
+
enqueue_process_trigger_job
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def create_trigger
|
20
|
+
context.trigger = shop.flow_triggers.create!(
|
21
|
+
title: title,
|
22
|
+
resource_name: resource_name,
|
23
|
+
resource_url: resource_url,
|
24
|
+
properties: properties
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def enqueue_process_trigger_job
|
29
|
+
ProcessTriggerJob.perform_later(shop, trigger)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'interactor'
|
2
|
+
|
3
|
+
module DiscoApp
|
4
|
+
module Flow
|
5
|
+
class ProcessAction
|
6
|
+
|
7
|
+
include Interactor
|
8
|
+
|
9
|
+
delegate :action, to: :context
|
10
|
+
delegate :action_service_class, to: :context
|
11
|
+
|
12
|
+
def call
|
13
|
+
validate_action
|
14
|
+
find_action_service_class
|
15
|
+
execute_action_service_class
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def validate_action
|
21
|
+
context.fail! unless action.pending?
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_action_service_class
|
25
|
+
context.action_service_class =
|
26
|
+
action.action_id.classify.safe_constantize ||
|
27
|
+
%(Flow::Actions::#{action.action_id.to_s.classify}).safe_constantize
|
28
|
+
|
29
|
+
return unless action_service_class.nil?
|
30
|
+
|
31
|
+
update_action(false, ["Could not find service class for #{action.action_id}"])
|
32
|
+
context.fail!
|
33
|
+
end
|
34
|
+
|
35
|
+
def execute_action_service_class
|
36
|
+
result = action_service_class.call(shop: action.shop, properties: action.properties)
|
37
|
+
update_action(result.success?, result.errors)
|
38
|
+
end
|
39
|
+
|
40
|
+
def update_action(success, errors)
|
41
|
+
action.update!(
|
42
|
+
status: success ? Action.statuses[:succeeded] : Action.statuses[:failed],
|
43
|
+
processing_errors: success ? [] : errors,
|
44
|
+
processed_at: Time.current
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'interactor'
|
2
|
+
|
3
|
+
module DiscoApp
|
4
|
+
module Flow
|
5
|
+
class ProcessTrigger
|
6
|
+
|
7
|
+
include Interactor
|
8
|
+
|
9
|
+
delegate :trigger, to: :context
|
10
|
+
delegate :api_success, :api_errors, to: :context
|
11
|
+
|
12
|
+
def call
|
13
|
+
validate_trigger
|
14
|
+
make_api_request unless trigger_not_in_use?
|
15
|
+
update_trigger
|
16
|
+
fail_if_errors_present
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def validate_trigger
|
22
|
+
context.fail! unless trigger.pending?
|
23
|
+
end
|
24
|
+
|
25
|
+
def make_api_request
|
26
|
+
context.api_success, context.api_errors = api_client.create_flow_trigger(
|
27
|
+
trigger.title,
|
28
|
+
trigger.resource_name,
|
29
|
+
trigger.resource_url,
|
30
|
+
trigger.properties
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def update_trigger
|
35
|
+
trigger.update!(
|
36
|
+
status: trigger_status,
|
37
|
+
processing_errors: processing_errors,
|
38
|
+
processed_at: Time.current
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def trigger_status
|
43
|
+
return Trigger.statuses[:skipped] if trigger_not_in_use?
|
44
|
+
|
45
|
+
api_success ? Trigger.statuses[:succeeded] : Trigger.statuses[:failed]
|
46
|
+
end
|
47
|
+
|
48
|
+
def processing_errors
|
49
|
+
return [] if trigger_not_in_use?
|
50
|
+
return [] if api_success
|
51
|
+
api_errors
|
52
|
+
end
|
53
|
+
|
54
|
+
def fail_if_errors_present
|
55
|
+
context.fail! unless trigger_not_in_use? || api_success
|
56
|
+
end
|
57
|
+
|
58
|
+
def api_client
|
59
|
+
@api_client ||= DiscoApp::GraphqlClient.new(trigger.shop)
|
60
|
+
end
|
61
|
+
|
62
|
+
def trigger_not_in_use?
|
63
|
+
trigger_usage.present? && !trigger_usage.has_enabled_flow?
|
64
|
+
end
|
65
|
+
|
66
|
+
def trigger_usage
|
67
|
+
@trigger_usage ||= TriggerUsage.find_by(shop: trigger.shop, flow_trigger_definition_id: trigger.title)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'interactor'
|
2
|
+
|
3
|
+
module DiscoApp
|
4
|
+
module Flow
|
5
|
+
class UpdateTriggerUsage
|
6
|
+
|
7
|
+
include Interactor
|
8
|
+
|
9
|
+
delegate :shop, :flow_trigger_definition_id, :has_enabled_flow, :timestamp, to: :context
|
10
|
+
delegate :trigger_usage, to: :context
|
11
|
+
|
12
|
+
def call
|
13
|
+
find_or_create_trigger_usage
|
14
|
+
update_trigger_usage
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def find_or_create_trigger_usage
|
20
|
+
context.trigger_usage = shop.flow_trigger_usages.create_or_find_by!(
|
21
|
+
flow_trigger_definition_id: flow_trigger_definition_id
|
22
|
+
)
|
23
|
+
rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation
|
24
|
+
context.fail!
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_trigger_usage
|
28
|
+
return if existing_timestamp_is_newer?
|
29
|
+
|
30
|
+
trigger_usage.update(
|
31
|
+
has_enabled_flow: has_enabled_flow,
|
32
|
+
timestamp: timestamp
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def existing_timestamp_is_newer?
|
37
|
+
trigger_usage.timestamp.present? && timestamp < trigger_usage.timestamp
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module DiscoApp
|
2
|
+
class PartnerAppService
|
3
|
+
|
4
|
+
def initialize(params)
|
5
|
+
@email = params[:email]
|
6
|
+
@password = params[:password]
|
7
|
+
@app_name = params[:app_name]
|
8
|
+
@app_url = params[:app_url]
|
9
|
+
@organization = params[:organization]
|
10
|
+
|
11
|
+
@agent = Mechanize.new do |a|
|
12
|
+
a.user_agent_alias = 'Mac Safari'
|
13
|
+
a.follow_meta_refresh = true
|
14
|
+
a.keep_alive = false
|
15
|
+
a.pre_connect_hooks << lambda do |_agent, request|
|
16
|
+
request['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_partner_app
|
22
|
+
begin
|
23
|
+
# Login to Shopify Partners
|
24
|
+
login
|
25
|
+
# Access Partner dashboard
|
26
|
+
org_link = organizations
|
27
|
+
dashboard = dashboard_page(org_link)
|
28
|
+
# Create App
|
29
|
+
apps_page = refresh_page(dashboard)
|
30
|
+
create_partner_app(apps_page)
|
31
|
+
# Configure newly created app with embedded app use
|
32
|
+
apps_page = refresh_page(dashboard)
|
33
|
+
embedded_admin_app(apps_page)
|
34
|
+
# Add Disco App icon
|
35
|
+
apps_page = refresh_page(dashboard)
|
36
|
+
add_disco_icon(apps_page)
|
37
|
+
# Fetch API credentials
|
38
|
+
apps_page = refresh_page(dashboard)
|
39
|
+
api_key, secret = api_credentials(apps_page)
|
40
|
+
rescue Mechanize::Error => e
|
41
|
+
puts 'Error while trying to create partner app'
|
42
|
+
puts "Error #{e}, message : #{e.message}"
|
43
|
+
return
|
44
|
+
end
|
45
|
+
# Add them to .env.local file
|
46
|
+
append_credentials(api_key, secret)
|
47
|
+
puts '#' * 80
|
48
|
+
puts 'New Partner App successfully created!'
|
49
|
+
puts 'API Credentials have been pasted to your .env.local file'
|
50
|
+
puts '#' * 80
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def login
|
56
|
+
@agent.get('https://accounts.shopify.com/login') do |page|
|
57
|
+
page.form do |form|
|
58
|
+
form['account[email]'] = @email
|
59
|
+
form['account[password]'] = @password
|
60
|
+
end.submit
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def organizations
|
65
|
+
organizations = @agent.get('https://partners.shopify.com/organizations/')
|
66
|
+
organizations.links.select { |link| link.text[/#{@organization}/] }.first.href
|
67
|
+
end
|
68
|
+
|
69
|
+
def dashboard_page(org_link)
|
70
|
+
@agent.get('https://partners.shopify.com' + org_link)
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_partner_app(apps_page)
|
74
|
+
apps_page.form do |form|
|
75
|
+
# App name
|
76
|
+
form['create_form[title]'] = @app_name
|
77
|
+
|
78
|
+
# App URL
|
79
|
+
form['create_form[application_url]'] = @app_url
|
80
|
+
|
81
|
+
# Accept TOS
|
82
|
+
if form['create_form[accepted]'].present?
|
83
|
+
form['create_form[accepted]'] = '1'
|
84
|
+
form.hiddens.last.value = 1
|
85
|
+
end
|
86
|
+
end.submit
|
87
|
+
end
|
88
|
+
|
89
|
+
def api_credentials(apps_page)
|
90
|
+
app = apps_page.link_with(text: @app_name).click
|
91
|
+
app_info = app.link_with(text: 'App info').click
|
92
|
+
add_whitelist_url(app_info)
|
93
|
+
api_key = app_info.search('#api_key').first.values[3]
|
94
|
+
secret = app_info.search('#settings_form_secrets').first.values[3]
|
95
|
+
[api_key, secret]
|
96
|
+
end
|
97
|
+
|
98
|
+
def embedded_admin_app(apps_page)
|
99
|
+
app = apps_page.link_with(text: @app_name).click
|
100
|
+
extensions = app.link_with(text: 'Extensions').click
|
101
|
+
extensions.form do |form|
|
102
|
+
form['extensions_form[embedded]'] = '1'
|
103
|
+
end.submit
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_disco_icon(apps_page)
|
107
|
+
app = apps_page.link_with(text: @app_name).click
|
108
|
+
app_info = app.link_with(text: 'App info').click
|
109
|
+
logo = DiscoApp::Engine.root.join('app', 'assets', 'images', 'disco_app', 'logo.png').to_s
|
110
|
+
app_info.form do |form|
|
111
|
+
form.file_uploads.first.file_name = logo
|
112
|
+
end.submit
|
113
|
+
end
|
114
|
+
|
115
|
+
# Write credentials of newly created app to .env.local file
|
116
|
+
def append_credentials(api_key, secret)
|
117
|
+
original_file = '.env.local'
|
118
|
+
new_file = original_file + '.new'
|
119
|
+
File.open(new_file, 'w') do |file|
|
120
|
+
File.foreach(original_file) do |line|
|
121
|
+
if line.include?('SHOPIFY_APP_API_KEY')
|
122
|
+
file.puts "SHOPIFY_APP_API_KEY=#{api_key}"
|
123
|
+
elsif line.include?('SHOPIFY_APP_SECRET')
|
124
|
+
file.puts "SHOPIFY_APP_SECRET=#{secret}"
|
125
|
+
else
|
126
|
+
file.puts line
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
File.delete(original_file)
|
131
|
+
File.rename(new_file, original_file)
|
132
|
+
end
|
133
|
+
|
134
|
+
def add_whitelist_url(app_info)
|
135
|
+
app_info.form do |form|
|
136
|
+
form['info_form[redirect_url_whitelist]'] = callback_url
|
137
|
+
end.submit
|
138
|
+
end
|
139
|
+
|
140
|
+
# Access the "Apps" section of the dashboard, also used to reload the dashboard
|
141
|
+
# When an action has been taken
|
142
|
+
def refresh_page(dashboard)
|
143
|
+
dashboard.link_with(text: ' Apps').click
|
144
|
+
end
|
145
|
+
|
146
|
+
def callback_url
|
147
|
+
[@app_url + '/auth/shopify/callback', @app_url + '/auth/shopify_user/callback'].join("\n")
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -5,12 +5,12 @@ class DiscoApp::ProxyService
|
|
5
5
|
def self.proxy_signature_is_valid?(query_string, secret)
|
6
6
|
query_hash = Rack::Utils.parse_query(query_string)
|
7
7
|
signature = query_hash.delete('signature').to_s
|
8
|
-
ActiveSupport::SecurityUtils.
|
8
|
+
ActiveSupport::SecurityUtils.secure_compare(calculated_signature(query_hash, secret), signature)
|
9
9
|
end
|
10
10
|
|
11
11
|
# Return the calculated signature for the given query hash and secret.
|
12
12
|
def self.calculated_signature(query_hash, secret)
|
13
|
-
sorted_params = query_hash.
|
13
|
+
sorted_params = query_hash.map{ |k, v| "#{k}=#{Array(v).join(',')}" }.sort.join
|
14
14
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, sorted_params)
|
15
15
|
end
|
16
16
|
|
@@ -3,12 +3,12 @@ class DiscoApp::RequestValidationService
|
|
3
3
|
def self.hmac_valid?(query_string, secret)
|
4
4
|
query_hash = Rack::Utils.parse_query(query_string)
|
5
5
|
hmac = query_hash.delete('hmac').to_s
|
6
|
-
ActiveSupport::SecurityUtils.
|
6
|
+
ActiveSupport::SecurityUtils.secure_compare(calculated_hmac(query_hash, secret), hmac)
|
7
7
|
end
|
8
8
|
|
9
9
|
# Return the calculated hmac for the given query hash and secret.
|
10
10
|
def self.calculated_hmac(query_hash, secret)
|
11
|
-
sorted_params = query_hash.
|
11
|
+
sorted_params = query_hash.map{ |k, v| "#{k}=#{Array(v).join(',')}" }.sort.join('&')
|
12
12
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, sorted_params)
|
13
13
|
end
|
14
14
|
|