disco_app 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +37 -0
  3. data/app/assets/components/disco_app/buttons/model-destroy-button.es6.jsx +31 -0
  4. data/app/assets/components/disco_app/forms/model-form.es6.jsx +64 -0
  5. data/app/assets/components/embedded_app/bar.es6.jsx +31 -0
  6. data/app/assets/components/shopify/buttons/_buttons.scss +546 -0
  7. data/app/assets/components/shopify/buttons/button.es6.jsx +15 -0
  8. data/app/assets/components/shopify/card/_card.scss +342 -0
  9. data/app/assets/components/shopify/card/card-header.es6.jsx +34 -0
  10. data/app/assets/components/shopify/card/card-section.es6.jsx +26 -0
  11. data/app/assets/components/shopify/card/card.es6.jsx +16 -0
  12. data/app/assets/components/shopify/typography/_typography.scss +23 -0
  13. data/app/assets/components/shopify/typography/ui-heading.es6.jsx +16 -0
  14. data/app/assets/components/shopify/ui-layout/_ui-layout.scss +157 -0
  15. data/app/assets/components/shopify/ui-layout/ui-annotated-section.es6.jsx +29 -0
  16. data/app/assets/components/shopify/ui-layout/ui-empty-state.es6.jsx +35 -0
  17. data/app/assets/components/shopify/ui-layout/ui-footer-help.es6.jsx +13 -0
  18. data/app/assets/components/shopify/ui-layout/ui-layout-item.es6.jsx +11 -0
  19. data/app/assets/components/shopify/ui-layout/ui-layout-section.es6.jsx +19 -0
  20. data/app/assets/components/shopify/ui-layout/ui-layout-sections.es6.jsx +11 -0
  21. data/app/assets/components/shopify/ui-layout/ui-layout.es6.jsx +11 -0
  22. data/app/assets/components/shopify/ui-layout/ui-page-actions.es6.jsx +13 -0
  23. data/app/assets/components/shopify/ui-layout/ui-page-actions__buttons.es6.jsx +27 -0
  24. data/app/assets/components/shopify/ui-stack/_ui-stack.scss +39 -0
  25. data/app/assets/components/shopify/ui-stack/ui-stack-item.es6.jsx +21 -0
  26. data/app/assets/components/shopify/ui-stack/ui-stack.es6.jsx +24 -0
  27. data/app/assets/images/disco_app/icon.svg +1 -0
  28. data/app/assets/images/disco_app/icons.svg +0 -0
  29. data/app/assets/javascripts/disco_app/components/custom/filterable_shop_list.js.jsx +61 -0
  30. data/app/assets/javascripts/disco_app/components/custom/inline-radio-options.es6.jsx +59 -0
  31. data/app/assets/javascripts/disco_app/components/custom/rules-editor.es6.jsx +432 -0
  32. data/app/assets/javascripts/disco_app/components/custom/shop_filter_query.js.jsx +13 -0
  33. data/app/assets/javascripts/disco_app/components/custom/shop_filter_tab.js.jsx +34 -0
  34. data/app/assets/javascripts/disco_app/components/custom/shop_filter_tabs.js.jsx +21 -0
  35. data/app/assets/javascripts/disco_app/components/custom/shop_list.js.jsx +142 -0
  36. data/app/assets/javascripts/disco_app/components/custom/shop_row.js.jsx +43 -0
  37. data/app/assets/javascripts/disco_app/components/custom/shopify_admin_link.js.jsx +29 -0
  38. data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_form.es6.jsx +72 -0
  39. data/app/assets/javascripts/disco_app/components/ui-kit/forms/base_input.es6.jsx +20 -0
  40. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-checkbox.es6.jsx +30 -0
  41. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-radio.es6.jsx +30 -0
  42. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-select.es6.jsx +45 -0
  43. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-text.es6.jsx +69 -0
  44. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-textarea.es6.jsx +48 -0
  45. data/app/assets/javascripts/disco_app/components/ui-kit/forms/input-time.es6.jsx +7 -0
  46. data/app/assets/javascripts/disco_app/components/ui-kit/forms/ui-form__element.es6.jsx +17 -0
  47. data/app/assets/javascripts/disco_app/components/ui-kit/forms/ui-form__group.es6.jsx +11 -0
  48. data/app/assets/javascripts/disco_app/components/ui-kit/forms/ui-form__section.es6.jsx +11 -0
  49. data/app/assets/javascripts/disco_app/components/ui-kit/icons/icon-chevron.es6.jsx +33 -0
  50. data/app/assets/javascripts/disco_app/components/ui-kit/icons/next-icon.es6.jsx +18 -0
  51. data/app/assets/javascripts/disco_app/components/ui-kit/input_select.es6.jsx +21 -0
  52. data/app/assets/javascripts/disco_app/components/ui-kit/tables/table.es6.jsx +27 -0
  53. data/app/assets/javascripts/disco_app/components.js +3 -0
  54. data/app/assets/javascripts/disco_app/disco_app.js +9 -0
  55. data/app/assets/javascripts/disco_app/frame.js +152 -0
  56. data/app/assets/javascripts/disco_app/shopify-turbolinks.js +7 -0
  57. data/app/assets/javascripts/disco_app/ui-kit.js +1 -0
  58. data/app/assets/stylesheets/disco_app/admin/_header.scss +75 -0
  59. data/app/assets/stylesheets/disco_app/admin/_layout.scss +32 -0
  60. data/app/assets/stylesheets/disco_app/admin/_nav.scss +184 -0
  61. data/app/assets/stylesheets/disco_app/admin.scss +11 -0
  62. data/app/assets/stylesheets/disco_app/disco_app.scss +24 -0
  63. data/app/assets/stylesheets/disco_app/frame/_buttons.scss +54 -0
  64. data/app/assets/stylesheets/disco_app/frame/_forms.scss +26 -0
  65. data/app/assets/stylesheets/disco_app/frame/_layout.scss +77 -0
  66. data/app/assets/stylesheets/disco_app/frame/_type.scss +25 -0
  67. data/app/assets/stylesheets/disco_app/frame.scss +10 -0
  68. data/app/assets/stylesheets/disco_app/mixins/_flexbox.scss +400 -0
  69. data/app/assets/stylesheets/disco_app/ui-kit/_ui-forms.scss +69 -0
  70. data/app/assets/stylesheets/disco_app/ui-kit/_ui-icons.scss +28 -0
  71. data/app/assets/stylesheets/disco_app/ui-kit/_ui-kit.scss +5116 -0
  72. data/app/assets/stylesheets/disco_app/ui-kit/_ui-layout.scss +15 -0
  73. data/app/assets/stylesheets/disco_app/ui-kit/_ui-tabs.scss +75 -0
  74. data/app/assets/stylesheets/disco_app/ui-kit/_ui-type.scss +13 -0
  75. data/app/controllers/disco_app/admin/app_settings_controller.rb +3 -0
  76. data/app/controllers/disco_app/admin/application_controller.rb +3 -0
  77. data/app/controllers/disco_app/admin/concerns/app_settings_controller.rb +24 -0
  78. data/app/controllers/disco_app/admin/concerns/authenticated_controller.rb +20 -0
  79. data/app/controllers/disco_app/admin/concerns/plans_controller.rb +54 -0
  80. data/app/controllers/disco_app/admin/concerns/shops_controller.rb +7 -0
  81. data/app/controllers/disco_app/admin/concerns/subscriptions_controller.rb +29 -0
  82. data/app/controllers/disco_app/admin/plans_controller.rb +3 -0
  83. data/app/controllers/disco_app/admin/resources/shops_controller.rb +3 -0
  84. data/app/controllers/disco_app/admin/shops_controller.rb +3 -0
  85. data/app/controllers/disco_app/admin/subscriptions_controller.rb +3 -0
  86. data/app/controllers/disco_app/charges_controller.rb +47 -0
  87. data/app/controllers/disco_app/concerns/app_proxy_controller.rb +40 -0
  88. data/app/controllers/disco_app/concerns/authenticated_controller.rb +56 -0
  89. data/app/controllers/disco_app/concerns/carrier_request_controller.rb +35 -0
  90. data/app/controllers/disco_app/frame_controller.rb +9 -0
  91. data/app/controllers/disco_app/install_controller.rb +27 -0
  92. data/app/controllers/disco_app/subscriptions_controller.rb +32 -0
  93. data/app/controllers/disco_app/webhooks_controller.rb +46 -0
  94. data/app/controllers/sessions_controller.rb +28 -0
  95. data/app/helpers/disco_app/application_helper.rb +68 -0
  96. data/app/jobs/disco_app/app_installed_job.rb +3 -0
  97. data/app/jobs/disco_app/app_uninstalled_job.rb +3 -0
  98. data/app/jobs/disco_app/concerns/app_installed_job.rb +39 -0
  99. data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +20 -0
  100. data/app/jobs/disco_app/concerns/render_asset_group_job.rb +8 -0
  101. data/app/jobs/disco_app/concerns/shop_update_job.rb +13 -0
  102. data/app/jobs/disco_app/concerns/subscription_changed_job.rb +7 -0
  103. data/app/jobs/disco_app/concerns/synchronise_carrier_service_job.rb +55 -0
  104. data/app/jobs/disco_app/concerns/synchronise_resources_job.rb +12 -0
  105. data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +52 -0
  106. data/app/jobs/disco_app/render_asset_group_job.rb +3 -0
  107. data/app/jobs/disco_app/shop_job.rb +27 -0
  108. data/app/jobs/disco_app/shop_update_job.rb +3 -0
  109. data/app/jobs/disco_app/subscription_changed_job.rb +3 -0
  110. data/app/jobs/disco_app/synchronise_carrier_service_job.rb +3 -0
  111. data/app/jobs/disco_app/synchronise_resources_job.rb +3 -0
  112. data/app/jobs/disco_app/synchronise_webhooks_job.rb +3 -0
  113. data/app/models/disco_app/app_settings.rb +3 -0
  114. data/app/models/disco_app/application_charge.rb +18 -0
  115. data/app/models/disco_app/concerns/app_settings.rb +7 -0
  116. data/app/models/disco_app/concerns/can_be_liquified.rb +45 -0
  117. data/app/models/disco_app/concerns/has_metafields.rb +48 -0
  118. data/app/models/disco_app/concerns/plan.rb +26 -0
  119. data/app/models/disco_app/concerns/plan_code.rb +15 -0
  120. data/app/models/disco_app/concerns/renders_assets.rb +166 -0
  121. data/app/models/disco_app/concerns/shop.rb +84 -0
  122. data/app/models/disco_app/concerns/subscription.rb +60 -0
  123. data/app/models/disco_app/concerns/synchronises.rb +58 -0
  124. data/app/models/disco_app/concerns/taggable.rb +16 -0
  125. data/app/models/disco_app/plan.rb +3 -0
  126. data/app/models/disco_app/plan_code.rb +3 -0
  127. data/app/models/disco_app/recurring_application_charge.rb +18 -0
  128. data/app/models/disco_app/session_storage.rb +18 -0
  129. data/app/models/disco_app/shop.rb +3 -0
  130. data/app/models/disco_app/subscription.rb +3 -0
  131. data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +100 -0
  132. data/app/resources/disco_app/admin/resources/shop_resource.rb +4 -0
  133. data/app/services/disco_app/carrier_request_service.rb +15 -0
  134. data/app/services/disco_app/charges_service.rb +81 -0
  135. data/app/services/disco_app/proxy_service.rb +17 -0
  136. data/app/services/disco_app/subscription_service.rb +46 -0
  137. data/app/services/disco_app/webhook_service.rb +30 -0
  138. data/app/views/disco_app/admin/app_settings/edit.html.erb +5 -0
  139. data/app/views/disco_app/admin/plans/_form.html.erb +72 -0
  140. data/app/views/disco_app/admin/plans/_plan_code_fields.html.erb +15 -0
  141. data/app/views/disco_app/admin/plans/edit.html.erb +7 -0
  142. data/app/views/disco_app/admin/plans/index.html.erb +43 -0
  143. data/app/views/disco_app/admin/plans/new.html.erb +7 -0
  144. data/app/views/disco_app/admin/shops/index.html.erb +13 -0
  145. data/app/views/disco_app/admin/subscriptions/edit.html.erb +33 -0
  146. data/app/views/disco_app/charges/activate.html.erb +1 -0
  147. data/app/views/disco_app/charges/create.html.erb +1 -0
  148. data/app/views/disco_app/charges/new.html.erb +23 -0
  149. data/app/views/disco_app/frame/frame.html.erb +36 -0
  150. data/app/views/disco_app/install/installing.html.erb +22 -0
  151. data/app/views/disco_app/install/uninstalling.html.erb +1 -0
  152. data/app/views/disco_app/proxy_errors/404.html.erb +1 -0
  153. data/app/views/disco_app/shared/_card.html.erb +14 -0
  154. data/app/views/disco_app/shared/_icons.html.erb +1 -0
  155. data/app/views/disco_app/shared/_section.html.erb +17 -0
  156. data/app/views/disco_app/subscriptions/new.html.erb +25 -0
  157. data/app/views/layouts/admin/_nav_items.erb +20 -0
  158. data/app/views/layouts/admin.html.erb +67 -0
  159. data/app/views/layouts/application.html.erb +18 -0
  160. data/app/views/layouts/embedded_app.html.erb +50 -0
  161. data/app/views/layouts/embedded_app_modal.html.erb +28 -0
  162. data/app/views/sessions/new.html.erb +28 -0
  163. data/config/routes.rb +63 -0
  164. data/db/migrate/20150525000000_create_shops_if_not_existent.rb +15 -0
  165. data/db/migrate/20150525162112_add_status_to_shops.rb +5 -0
  166. data/db/migrate/20150525171422_add_meta_to_shops.rb +11 -0
  167. data/db/migrate/20150629210346_add_charge_status_to_shop.rb +5 -0
  168. data/db/migrate/20150814214025_add_more_meta_to_shops.rb +15 -0
  169. data/db/migrate/20151017231302_create_disco_app_plans.rb +13 -0
  170. data/db/migrate/20151017232027_create_disco_app_subscriptions.rb +15 -0
  171. data/db/migrate/20151017234409_move_shop_to_disco_app_engine.rb +5 -0
  172. data/db/migrate/20160112233706_create_disco_app_sessions.rb +12 -0
  173. data/db/migrate/20160113194418_add_shop_id_to_disco_app_sessions.rb +6 -0
  174. data/db/migrate/20160223111044_create_disco_app_settings.rb +8 -0
  175. data/db/migrate/20160301223215_update_plans.rb +22 -0
  176. data/db/migrate/20160301224558_update_subscriptions.rb +13 -0
  177. data/db/migrate/20160302104816_create_disco_app_recurring_application_charges.rb +14 -0
  178. data/db/migrate/20160302105259_create_disco_app_application_charges.rb +14 -0
  179. data/db/migrate/20160302134728_drop_charge_status_from_shops.rb +5 -0
  180. data/db/migrate/20160302142941_add_shopify_attributes_to_charges.rb +8 -0
  181. data/db/migrate/20160331093148_create_disco_app_plan_codes.rb +14 -0
  182. data/db/migrate/20160401044420_add_status_to_plan_codes.rb +5 -0
  183. data/db/migrate/20160401045551_add_amount_and_plan_code_to_disco_app_subscriptions.rb +7 -0
  184. data/db/migrate/20160425205211_add_source_to_disco_app_subscriptions.rb +5 -0
  185. data/db/migrate/20160426033520_add_trial_period_days_to_disco_app_subscriptions.rb +5 -0
  186. data/db/migrate/20160513140727_add_name_to_disco_app_shops.rb +5 -0
  187. data/db/migrate/20160521135510_move_shop_to_synchronises.rb +61 -0
  188. data/lib/disco_app/configuration.rb +45 -0
  189. data/lib/disco_app/constants.rb +4 -0
  190. data/lib/disco_app/engine.rb +26 -0
  191. data/lib/disco_app/session.rb +14 -0
  192. data/lib/disco_app/support/file_fixtures.rb +23 -0
  193. data/lib/disco_app/test_help.rb +11 -0
  194. data/lib/disco_app/version.rb +3 -0
  195. data/lib/disco_app.rb +7 -0
  196. data/lib/generators/disco_app/USAGE +5 -0
  197. data/lib/generators/disco_app/disco_app_generator.rb +239 -0
  198. data/lib/generators/disco_app/templates/assets/javascripts/application.js +17 -0
  199. data/lib/generators/disco_app/templates/assets/javascripts/components.js +3 -0
  200. data/lib/generators/disco_app/templates/assets/stylesheets/application.scss +5 -0
  201. data/lib/generators/disco_app/templates/config/database.yml.tt +20 -0
  202. data/lib/generators/disco_app/templates/config/newrelic.yml +26 -0
  203. data/lib/generators/disco_app/templates/config/puma.rb +15 -0
  204. data/lib/generators/disco_app/templates/controllers/home_controller.rb +7 -0
  205. data/lib/generators/disco_app/templates/initializers/disco_app.rb +28 -0
  206. data/lib/generators/disco_app/templates/initializers/rollbar.rb +19 -0
  207. data/lib/generators/disco_app/templates/initializers/session_store.rb +2 -0
  208. data/lib/generators/disco_app/templates/initializers/shopify_app.rb +7 -0
  209. data/lib/generators/disco_app/templates/initializers/shopify_session_repository.rb +7 -0
  210. data/lib/generators/disco_app/templates/root/CHECKS +4 -0
  211. data/lib/generators/disco_app/templates/root/Procfile +2 -0
  212. data/lib/generators/disco_app/templates/views/home/index.html.erb +2 -0
  213. data/lib/tasks/carrier_service.rake +10 -0
  214. data/lib/tasks/database.rake +8 -0
  215. data/lib/tasks/sessions.rake +9 -0
  216. data/lib/tasks/shops.rake +10 -0
  217. data/lib/tasks/start.rake +3 -0
  218. data/lib/tasks/webhooks.rake +10 -0
  219. data/test/controllers/disco_app/admin/shops_controller_test.rb +54 -0
  220. data/test/controllers/disco_app/charges_controller_test.rb +99 -0
  221. data/test/controllers/disco_app/install_controller_test.rb +50 -0
  222. data/test/controllers/disco_app/subscriptions_controller_test.rb +68 -0
  223. data/test/controllers/disco_app/webhooks_controller_test.rb +58 -0
  224. data/test/controllers/home_controller_test.rb +92 -0
  225. data/test/controllers/proxy_controller_test.rb +42 -0
  226. data/test/disco_app_test.rb +7 -0
  227. data/test/dummy/Rakefile +6 -0
  228. data/test/dummy/app/assets/javascripts/application.js +17 -0
  229. data/test/dummy/app/assets/stylesheets/application.scss +5 -0
  230. data/test/dummy/app/controllers/application_controller.rb +6 -0
  231. data/test/dummy/app/controllers/carrier_request_controller.rb +10 -0
  232. data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +8 -0
  233. data/test/dummy/app/controllers/home_controller.rb +7 -0
  234. data/test/dummy/app/controllers/proxy_controller.rb +8 -0
  235. data/test/dummy/app/helpers/application_helper.rb +2 -0
  236. data/test/dummy/app/jobs/carts_update_job.rb +7 -0
  237. data/test/dummy/app/jobs/disco_app/app_installed_job.rb +16 -0
  238. data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +11 -0
  239. data/test/dummy/app/jobs/products_create_job.rb +7 -0
  240. data/test/dummy/app/jobs/products_delete_job.rb +7 -0
  241. data/test/dummy/app/jobs/products_update_job.rb +7 -0
  242. data/test/dummy/app/models/cart.rb +24 -0
  243. data/test/dummy/app/models/disco_app/shop.rb +15 -0
  244. data/test/dummy/app/models/js_configuration.rb +8 -0
  245. data/test/dummy/app/models/product.rb +9 -0
  246. data/test/dummy/app/models/widget_configuration.rb +10 -0
  247. data/test/dummy/app/views/assets/script_tag.js.erb +1 -0
  248. data/test/dummy/app/views/assets/test.js.erb +1 -0
  249. data/test/dummy/app/views/assets/widget.js.erb +2 -0
  250. data/test/dummy/app/views/assets/widget.scss.erb +3 -0
  251. data/test/dummy/app/views/home/index.html.erb +2 -0
  252. data/test/dummy/app/views/snippets/widget.liquid.erb +1 -0
  253. data/test/dummy/bin/bundle +3 -0
  254. data/test/dummy/bin/rails +4 -0
  255. data/test/dummy/bin/rake +4 -0
  256. data/test/dummy/bin/setup +29 -0
  257. data/test/dummy/config/application.rb +38 -0
  258. data/test/dummy/config/boot.rb +5 -0
  259. data/test/dummy/config/database.codeship.yml +23 -0
  260. data/test/dummy/config/database.gitlab-ci.yml +24 -0
  261. data/test/dummy/config/database.yml +20 -0
  262. data/test/dummy/config/environment.rb +5 -0
  263. data/test/dummy/config/environments/development.rb +41 -0
  264. data/test/dummy/config/environments/production.rb +85 -0
  265. data/test/dummy/config/environments/test.rb +42 -0
  266. data/test/dummy/config/initializers/assets.rb +11 -0
  267. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  268. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  269. data/test/dummy/config/initializers/disco_app.rb +28 -0
  270. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  271. data/test/dummy/config/initializers/inflections.rb +16 -0
  272. data/test/dummy/config/initializers/mime_types.rb +4 -0
  273. data/test/dummy/config/initializers/omniauth.rb +9 -0
  274. data/test/dummy/config/initializers/session_store.rb +2 -0
  275. data/test/dummy/config/initializers/shopify_app.rb +7 -0
  276. data/test/dummy/config/initializers/shopify_session_repository.rb +7 -0
  277. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  278. data/test/dummy/config/locales/en.yml +23 -0
  279. data/test/dummy/config/routes.rb +11 -0
  280. data/test/dummy/config/secrets.yml +22 -0
  281. data/test/dummy/config.ru +4 -0
  282. data/test/dummy/db/migrate/20160307182229_create_products.rb +11 -0
  283. data/test/dummy/db/migrate/20160530160739_create_asset_models.rb +19 -0
  284. data/test/dummy/db/migrate/20161105054746_create_carts.rb +13 -0
  285. data/test/dummy/db/schema.rb +152 -0
  286. data/test/dummy/public/404.html +67 -0
  287. data/test/dummy/public/422.html +67 -0
  288. data/test/dummy/public/500.html +66 -0
  289. data/test/dummy/public/favicon.ico +0 -0
  290. data/test/fixtures/api/widget_store/assets/create_script_tag_js_request.json +6 -0
  291. data/test/fixtures/api/widget_store/assets/create_script_tag_js_response.json +12 -0
  292. data/test/fixtures/api/widget_store/assets/create_script_tag_request.json +6 -0
  293. data/test/fixtures/api/widget_store/assets/create_script_tag_response.json +10 -0
  294. data/test/fixtures/api/widget_store/assets/create_test_js_request.json +6 -0
  295. data/test/fixtures/api/widget_store/assets/create_test_js_response.json +12 -0
  296. data/test/fixtures/api/widget_store/assets/create_widget_js_request.json +6 -0
  297. data/test/fixtures/api/widget_store/assets/create_widget_js_response.json +12 -0
  298. data/test/fixtures/api/widget_store/assets/create_widget_liquid_request.json +6 -0
  299. data/test/fixtures/api/widget_store/assets/create_widget_liquid_response.json +12 -0
  300. data/test/fixtures/api/widget_store/assets/create_widget_scss_request.json +6 -0
  301. data/test/fixtures/api/widget_store/assets/create_widget_scss_response.json +12 -0
  302. data/test/fixtures/api/widget_store/assets/get_script_tags_empty_request.json +1 -0
  303. data/test/fixtures/api/widget_store/assets/get_script_tags_empty_response.json +1 -0
  304. data/test/fixtures/api/widget_store/assets/get_script_tags_preexisting_request.json +1 -0
  305. data/test/fixtures/api/widget_store/assets/get_script_tags_preexisting_response.json +12 -0
  306. data/test/fixtures/api/widget_store/assets/update_script_tag_request.json +10 -0
  307. data/test/fixtures/api/widget_store/assets/update_script_tag_response.json +10 -0
  308. data/test/fixtures/api/widget_store/carrier_services.json +1 -0
  309. data/test/fixtures/api/widget_store/carrier_services_create.json +8 -0
  310. data/test/fixtures/api/widget_store/charges/activate_application_charge_request.json +16 -0
  311. data/test/fixtures/api/widget_store/charges/activate_application_charge_response.json +1 -0
  312. data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_request.json +20 -0
  313. data/test/fixtures/api/widget_store/charges/activate_recurring_application_charge_response.json +1 -0
  314. data/test/fixtures/api/widget_store/charges/create_application_charge_request.json +9 -0
  315. data/test/fixtures/api/widget_store/charges/create_application_charge_response.json +16 -0
  316. data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_request.json +9 -0
  317. data/test/fixtures/api/widget_store/charges/create_recurring_application_charge_response.json +20 -0
  318. data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_request.json +9 -0
  319. data/test/fixtures/api/widget_store/charges/create_second_recurring_application_charge_response.json +20 -0
  320. data/test/fixtures/api/widget_store/charges/get_accepted_application_charge_response.json +16 -0
  321. data/test/fixtures/api/widget_store/charges/get_accepted_recurring_application_charge_response.json +20 -0
  322. data/test/fixtures/api/widget_store/charges/get_declined_application_charge_response.json +16 -0
  323. data/test/fixtures/api/widget_store/charges/get_declined_recurring_application_charge_response.json +20 -0
  324. data/test/fixtures/api/widget_store/charges/get_pending_application_charge_response.json +16 -0
  325. data/test/fixtures/api/widget_store/charges/get_pending_recurring_application_charge_response.json +20 -0
  326. data/test/fixtures/api/widget_store/products/write_metafields_multiple_namespaces_request.json +31 -0
  327. data/test/fixtures/api/widget_store/products/write_metafields_multiple_namespaces_response.json +1 -0
  328. data/test/fixtures/api/widget_store/products/write_metafields_single_namespace_request.json +19 -0
  329. data/test/fixtures/api/widget_store/products/write_metafields_single_namespace_response.json +1 -0
  330. data/test/fixtures/api/widget_store/shop.json +46 -0
  331. data/test/fixtures/api/widget_store/webhooks.json +1 -0
  332. data/test/fixtures/assets/test.js +1 -0
  333. data/test/fixtures/assets/test.min.js +1 -0
  334. data/test/fixtures/carts.yml +5 -0
  335. data/test/fixtures/disco_app/application_charges.yml +11 -0
  336. data/test/fixtures/disco_app/plan_codes.yml +13 -0
  337. data/test/fixtures/disco_app/plans.yml +37 -0
  338. data/test/fixtures/disco_app/recurring_application_charges.yml +11 -0
  339. data/test/fixtures/disco_app/shops.yml +10 -0
  340. data/test/fixtures/disco_app/subscriptions.yml +22 -0
  341. data/test/fixtures/js_configurations.yml +3 -0
  342. data/test/fixtures/liquid/model.liquid +8 -0
  343. data/test/fixtures/products.yml +4 -0
  344. data/test/fixtures/webhooks/app_uninstalled.json +46 -0
  345. data/test/fixtures/webhooks/cart_updated.json +28 -0
  346. data/test/fixtures/webhooks/product_created.json +167 -0
  347. data/test/fixtures/webhooks/product_deleted.json +3 -0
  348. data/test/fixtures/webhooks/product_updated.json +167 -0
  349. data/test/fixtures/widget_configurations.yml +4 -0
  350. data/test/integration/synchronises_test.rb +62 -0
  351. data/test/jobs/disco_app/app_installed_job_test.rb +57 -0
  352. data/test/jobs/disco_app/app_uninstalled_job_test.rb +30 -0
  353. data/test/jobs/disco_app/synchronise_carrier_service_job_test.rb +25 -0
  354. data/test/jobs/disco_app/synchronise_webhooks_job_test.rb +30 -0
  355. data/test/models/disco_app/can_be_liquified_test.rb +55 -0
  356. data/test/models/disco_app/has_metafields_test.rb +40 -0
  357. data/test/models/disco_app/plan_test.rb +5 -0
  358. data/test/models/disco_app/renders_assets_test.rb +109 -0
  359. data/test/models/disco_app/session_test.rb +31 -0
  360. data/test/models/disco_app/shop_test.rb +43 -0
  361. data/test/models/disco_app/subscription_test.rb +19 -0
  362. data/test/services/disco_app/charges_service_test.rb +112 -0
  363. data/test/services/disco_app/subscription_service_test.rb +60 -0
  364. data/test/support/test_file_fixtures.rb +29 -0
  365. data/test/support/test_shopify_api.rb +16 -0
  366. data/test/test_helper.rb +55 -0
  367. metadata +893 -0
@@ -0,0 +1,239 @@
1
+ class DiscoAppGenerator < Rails::Generators::Base
2
+
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ # Copy a number of template files to the top-level directory of our application:
6
+ #
7
+ # - .env and .env.local for settings environment variables in development with dotenv-rails;
8
+ # - Slightly customised version of the default Rails .gitignore;
9
+ # - Default simple Procfile for Heroku.
10
+ #
11
+ def copy_root_files
12
+ %w(.env .env.local .gitignore Procfile CHECKS).each do |file|
13
+ copy_file "root/#{file}", file
14
+ end
15
+ end
16
+
17
+ # Remove a number of root files.
18
+ def remove_root_files
19
+ %w(README.rdoc).each do |file|
20
+ remove_file file
21
+ end
22
+ end
23
+
24
+ # Configure the application's Gemfile.
25
+ def configure_gems
26
+ # Remove sqlite from the general Gemfile.
27
+ gsub_file 'Gemfile', /^# Use sqlite3 as the database for Active Record\ngem 'sqlite3'/m, ''
28
+
29
+ # Add gems common to all environments.
30
+ gem 'shopify_app', '~> 6.4.1'
31
+ gem 'sidekiq', '~> 4.0.2'
32
+ gem 'puma', '~> 2.14.0'
33
+ gem 'activerecord-session_store', '~> 1.0.0'
34
+ gem 'activeresource', github: 'shopify/activeresource', tag: '4.2-threadsafe'
35
+ gem 'rails-bigint-pk', '~> 1.2.0'
36
+ gem 'acts_as_singleton', '~> 0.0.8'
37
+ gem 'pg', '~> 0.18.3'
38
+ gem 'react-rails', '~> 1.6.0'
39
+ gem 'classnames-rails', '~> 2.1.5'
40
+ gem 'active_link_to', '~> 1.0.2'
41
+ gem 'premailer-rails', '~> 1.8.2'
42
+ gem 'nokogiri', '~> 1.6.8'
43
+ gem 'render_anywhere', '~> 0.0.12', require: false
44
+
45
+ # Add gems for development and testing only.
46
+ gem_group :development, :test do
47
+ gem 'dotenv-rails', '~> 2.0.2'
48
+ gem 'minitest-reporters', '~> 1.0.19'
49
+ gem 'guard', '~> 2.13.0'
50
+ gem 'guard-minitest', '~> 2.4.4'
51
+ end
52
+
53
+ # Add gems for production only.
54
+ gem_group :production do
55
+ gem 'rails_12factor', '~> 0.0.3'
56
+ gem 'mailgun_rails', '~> 0.7.0'
57
+ end
58
+
59
+ # Add monitoring gems to Gemfile
60
+ gem 'rollbar', '~> 2.8.0'
61
+ gem 'oj', '~> 2.14.5'
62
+ gem 'newrelic_rpm', '~> 3.15.2.317'
63
+ end
64
+
65
+ # copy template for pg configuration
66
+ def update_database_config
67
+ template 'config/database.yml.tt'
68
+ end
69
+
70
+ # Run bundle install to add our new gems before running tasks.
71
+ def bundle_install
72
+ Bundler.with_clean_env do
73
+ run 'bundle install'
74
+ end
75
+ end
76
+
77
+ # Make any required adjustments to the application configuration.
78
+ def configure_application
79
+ # The force_ssl flag is commented by default for production.
80
+ # Uncomment to ensure config.force_ssl = true in production.
81
+ uncomment_lines 'config/environments/production.rb', /force_ssl/
82
+
83
+ # Set time zone to UTC
84
+ application "config.time_zone = 'UTC'"
85
+ application "# Ensure UTC is the default timezone"
86
+
87
+ # Set server side rendereing for components.js
88
+ application "config.react.server_renderer_options = {\nfiles: ['components.js'], # files to load for prerendering\n}"
89
+ application "# Enable server side react rendering"
90
+
91
+ # Set defaults for various charge attributes.
92
+ application "config.x.shopify_charges_default_trial_days = 14\n"
93
+ application "config.x.shopify_charges_default_price = 10.00"
94
+ application "config.x.shopify_charges_default_type = :recurring"
95
+ application "# Set defaults for charges created by the application"
96
+
97
+ # Set the "real charges" config variable to false explicitly by default.
98
+ # Only in production do we read from the environment variable and
99
+ # potentially have it become true.
100
+ application "config.x.shopify_charges_real = false\n"
101
+ application "# Explicitly prevent real charges being created by default"
102
+ application "config.x.shopify_charges_real = ENV['SHOPIFY_CHARGES_REAL'] == 'true'\n", env: :production
103
+ application "# Allow real charges in production with an ENV variable", env: :production
104
+
105
+ # Configure session storage.
106
+ application "ActiveRecord::SessionStore::Session.table_name = 'disco_app_sessions'"
107
+ application "ActionDispatch::Session::ActiveRecordStore.session_class = DiscoApp::Session"
108
+ application "# Configure custom session storage"
109
+
110
+ # Set Sidekiq as the queue adapter in production.
111
+ application "config.active_job.queue_adapter = :sidekiq\n", env: :production
112
+ application "# Use Sidekiq as the active job backend", env: :production
113
+
114
+ # Ensure the application configuration uses the DEFAULT_HOST environment
115
+ # variable to set up support for reverse routing absolute URLS (needed when
116
+ # generating Webhook URLs for example).
117
+ application "routes.default_url_options[:host] = ENV['DEFAULT_HOST']\n"
118
+ application "# Set the default host for absolute URL routing purposes"
119
+
120
+ # Configure React in development and production.
121
+ application "config.react.variant = :development", env: :development
122
+ application "# Use development variant of React in development.", env: :development
123
+ application "config.react.variant = :production", env: :production
124
+ application "# Use production variant of React in production.", env: :production
125
+
126
+ # Copy over the default puma configuration.
127
+ copy_file 'config/puma.rb', 'config/puma.rb'
128
+
129
+ # Mail configuration
130
+ configuration = <<-CONFIG.strip_heredoc
131
+
132
+ # Configure ActionMailer to use MailGun
133
+ if ENV['MAILGUN_API_KEY']
134
+ config.action_mailer.delivery_method = :mailgun
135
+ config.action_mailer.mailgun_settings = {
136
+ api_key: ENV['MAILGUN_API_KEY'],
137
+ domain: ENV['MAILGUN_API_DOMAIN']
138
+ }
139
+ end
140
+ CONFIG
141
+ application configuration, env: :production
142
+
143
+ # Monitoring configuration
144
+ copy_file 'initializers/rollbar.rb', 'config/initializers/rollbar.rb'
145
+ copy_file 'config/newrelic.yml', 'config/newrelic.yml'
146
+ end
147
+
148
+
149
+ # Add entries to .env and .env.local
150
+ def add_env_variables
151
+ configuration = <<-CONFIG.strip_heredoc
152
+
153
+ MAILGUN_API_KEY=
154
+ MAILGUN_API_DOMAIN=
155
+ CONFIG
156
+ append_to_file '.env', configuration
157
+ append_to_file '.env.local', configuration
158
+ end
159
+
160
+ # Set up routes.
161
+ def setup_routes
162
+ route "mount DiscoApp::Engine, at: '/'"
163
+ end
164
+
165
+ # Run generators.
166
+ def run_generators
167
+ generate 'shopify_app:install'
168
+ generate 'shopify_app:home_controller'
169
+ generate 'bigint_pk:install'
170
+ generate 'react:install'
171
+ end
172
+
173
+ # Copy template files to the appropriate location. In some cases, we'll be
174
+ # overwriting or removing existing files or those created by ShopifyApp.
175
+ def copy_and_remove_files
176
+ # Copy initializers
177
+ copy_file 'initializers/shopify_app.rb', 'config/initializers/shopify_app.rb'
178
+ copy_file 'initializers/disco_app.rb', 'config/initializers/disco_app.rb'
179
+ copy_file 'initializers/shopify_session_repository.rb', 'config/initializers/shopify_session_repository.rb'
180
+ copy_file 'initializers/session_store.rb', 'config/initializers/session_store.rb'
181
+
182
+ # Copy default home controller and view
183
+ copy_file 'controllers/home_controller.rb', 'app/controllers/home_controller.rb'
184
+ copy_file 'views/home/index.html.erb', 'app/views/home/index.html.erb'
185
+
186
+ # Copy assets
187
+ copy_file 'assets/javascripts/application.js', 'app/assets/javascripts/application.js'
188
+ copy_file 'assets/javascripts/components.js', 'app/assets/javascripts/components.js'
189
+ copy_file 'assets/stylesheets/application.scss', 'app/assets/stylesheets/application.scss'
190
+
191
+ # Remove application.css
192
+ remove_file 'app/assets/stylesheets/application.css'
193
+
194
+ # Remove the layout files created by ShopifyApp
195
+ remove_file 'app/views/layouts/application.html.erb'
196
+ remove_file 'app/views/layouts/embedded_app.html.erb'
197
+ end
198
+
199
+ # Add the Disco App test helper to test/test_helper.rb
200
+ def add_test_helper
201
+ inject_into_file 'test/test_helper.rb', "require 'disco_app/test_help'\n", { after: "require 'rails/test_help'\n" }
202
+ end
203
+
204
+ # Copy engine migrations over.
205
+ def install_migrations
206
+ rake 'disco_app:install:migrations'
207
+ end
208
+
209
+ # Create PG database
210
+ def create_database
211
+ rake 'db:create'
212
+ end
213
+
214
+ # Run migrations.
215
+ def migrate
216
+ rake 'db:migrate'
217
+ end
218
+
219
+ # Lock down the application to a specific Ruby version:
220
+ #
221
+ # - Via .ruby-version file for rbenv in development;
222
+ # - Via a Gemfile line in production.
223
+ #
224
+ # This should be the last operation, to allow all other operations to run in the initial Ruby version.
225
+ def set_ruby_version
226
+ copy_file 'root/.ruby-version', '.ruby-version'
227
+ prepend_to_file 'Gemfile', "ruby '2.3.3'\n"
228
+ end
229
+
230
+ private
231
+
232
+ # This method of finding the component.js manifest taken from the
233
+ # install generator in react-rails.
234
+ # See https://github.com/reactjs/react-rails/blob/3f0af13fa755d6e95969c17728d0354c234f3a37/lib/generators/react/install_generator.rb#L53-L55
235
+ def components
236
+ Pathname.new(destination_root).join('app/assets/javascripts', 'components.js')
237
+ end
238
+
239
+ end
@@ -0,0 +1,17 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require turbolinks
16
+ //= require disco_app/disco_app
17
+ //= require_tree .
@@ -0,0 +1,3 @@
1
+ //= require react-server
2
+ //= require disco_app/components
3
+ //= require_tree ./components
@@ -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";
@@ -0,0 +1,20 @@
1
+ default: &default
2
+ adapter: postgresql
3
+ encoding: unicode
4
+ pool: 5
5
+ timeout: 5000
6
+
7
+ development:
8
+ <<: *default
9
+ host: localhost
10
+ port: 5432
11
+ database: <%= Rails.application.class.parent_name.downcase %>
12
+
13
+ test:
14
+ <<: *default
15
+ host: localhost
16
+ port: 5432
17
+ database: <%= Rails.application.class.parent_name.downcase %>_test
18
+
19
+ production:
20
+ <<: *default
@@ -0,0 +1,26 @@
1
+ # This file configures the New Relic Agent.
2
+ #
3
+ # For full documentation of agent configuration options, please refer to
4
+ # https://docs.newrelic.com/docs/agents/ruby-agent/installation-configuration/ruby-agent-configuration
5
+
6
+ common: &default_settings
7
+ license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %>
8
+ app_name: <%= ENV['SHOPIFY_APP_NAME'] || 'Unknown App' %>
9
+
10
+ # To disable the agent regardless of other settings, uncomment the following:
11
+ # agent_enabled: false
12
+
13
+ # Logging level for log/newrelic_agent.log
14
+ log_level: info
15
+
16
+ development:
17
+ <<: *default_settings
18
+ app_name: <%= ENV['SHOPIFY_APP_NAME'] || 'Unknown App' %> (Development)
19
+ developer_mode: true
20
+
21
+ test:
22
+ <<: *default_settings
23
+ monitor_mode: false
24
+
25
+ production:
26
+ <<: *default_settings
@@ -0,0 +1,15 @@
1
+ workers Integer(ENV['WEB_CONCURRENCY'] || 2)
2
+ threads_count = Integer(ENV['MAX_THREADS'] || 5)
3
+ threads threads_count, threads_count
4
+
5
+ preload_app!
6
+
7
+ rackup DefaultRackup
8
+ port ENV['PORT'] || 3000
9
+ environment ENV['RACK_ENV'] || 'development'
10
+
11
+ on_worker_boot do
12
+ # Worker specific setup for Rails 4.1+
13
+ # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
14
+ ActiveRecord::Base.establish_connection
15
+ end
@@ -0,0 +1,7 @@
1
+ class HomeController < ApplicationController
2
+ include DiscoApp::Concerns::AuthenticatedController
3
+
4
+ def index
5
+ end
6
+
7
+ end
@@ -0,0 +1,28 @@
1
+ DiscoApp::Engine.routes.default_url_options[:host] = ENV['DEFAULT_HOST']
2
+
3
+ DiscoApp.configure do |config|
4
+ # Required configuration.
5
+ config.app_name = ENV['SHOPIFY_APP_NAME']
6
+
7
+ # Set a list of webhook topics to listen for.
8
+ # See https://help.shopify.com/api/reference/webhook.
9
+ config.webhook_topics = []
10
+
11
+ # Set the below if using an application proxy.
12
+ config.app_proxy_prefix = ENV['SHOPIFY_APP_PROXY_PREFIX']
13
+
14
+ # Set the below if providing a carrier service endpoint.
15
+ # Note that if using a URL helper to set the endpoint, we use a lambda
16
+ # function to ensure that the URL helper is only evaluated when we need it.
17
+ # config.carrier_service_callback_url = -> { Rails.application.routes.url_helpers.carrier_service_callback_url }
18
+
19
+ # Set the below to create real Shopify charges.
20
+ config.real_charges = ENV['SHOPIFY_REAL_CHARGES'] === 'true'
21
+
22
+ # Optional configuration. These flags are only respected in the development
23
+ # environment and will have no effect in production.
24
+ config.skip_proxy_verification = ENV['SKIP_PROXY_VERIFICATION'] == 'true'
25
+ config.skip_webhook_verification = ENV['SKIP_WEBHOOK_VERIFICATION'] == 'true'
26
+ config.skip_carrier_request_verification = ENV['SKIP_CARRIER_REQUEST_VERIFICATION'] == 'true'
27
+ config.skip_oauth = ENV['SKIP_OAUTH'] == 'true'
28
+ end
@@ -0,0 +1,19 @@
1
+ Rollbar.configure do |config|
2
+ # Fetch the access token from the environment.
3
+ config.access_token = ENV['ROLLBAR_ACCESS_TOKEN']
4
+
5
+ # Only use Rollbar in production when there's a token configured.
6
+ unless config.access_token and Rails.env.production?
7
+ config.enabled = false
8
+ end
9
+
10
+ # Enable delayed reporting (using Sidekiq)
11
+ config.use_sidekiq
12
+
13
+ # Add custom handlers.
14
+ config.before_process << proc do |options|
15
+ if options[:exception].is_a?(ActiveResource::ClientError) and options[:exception].message.include?('Too Many Requests')
16
+ raise Rollbar::Ignore
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,2 @@
1
+ # Use an ActiveRecord-based session store.
2
+ Rails.application.config.session_store :active_record_store, :key => '_disco_app_session'
@@ -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
@@ -0,0 +1,4 @@
1
+ WAIT=5
2
+ ATTEMPTS=6
3
+ /login
4
+
@@ -0,0 +1,2 @@
1
+ web: bundle exec puma -C ./config/puma.rb
2
+ worker: bundle exec sidekiq -c 5 -v -q default -q mailers -q rollbar
@@ -0,0 +1,2 @@
1
+ <% provide(:title, 'Welcome') %>
2
+ <h1>Welcome</h1>
@@ -0,0 +1,10 @@
1
+ namespace :carrier_service do
2
+
3
+ desc 'Synchronise carrier service across all installed shops.'
4
+ task sync: :environment do
5
+ DiscoApp::Shop.installed.has_active_shopify_plan.each do |shop|
6
+ DiscoApp::SynchroniseCarrierServiceJob.perform_later(shop)
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,8 @@
1
+ namespace :database do
2
+ desc "update postgres sequence numbers in case database has been migrated"
3
+ task update_sequences: :environment do
4
+ ActiveRecord::Base.connection.tables.each do |t|
5
+ ActiveRecord::Base.connection.reset_pk_sequence!(t)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ namespace :sessions do
2
+
3
+ desc 'Clean out any stale sessions.'
4
+ task clean: [:environment, 'db:load_config'] do
5
+ threshold = (ENV['SESSIONS_CLEAN_THRESHOLD_DAYS'] || 30).to_i.days.ago
6
+ ActiveRecord::Base.connection.execute("DELETE FROM #{ActiveRecord::SessionStore::Session.table_name} WHERE updated_at < '#{threshold}'")
7
+ end
8
+
9
+ end
@@ -0,0 +1,10 @@
1
+ namespace :shops do
2
+
3
+ desc 'Synchronise shop data across all installed shops.'
4
+ task sync: :environment do
5
+ DiscoApp::Shop.installed.has_active_shopify_plan.each do |shop|
6
+ DiscoApp::ShopUpdateJob.perform_later(shop)
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ task start: :environment do
2
+ system 'bundle exec rails server -b 127.0.0.1 -p 3000'
3
+ end
@@ -0,0 +1,10 @@
1
+ namespace :webhooks do
2
+
3
+ desc 'Synchronise webhooks across all installed shops.'
4
+ task sync: :environment do
5
+ DiscoApp::Shop.installed.has_active_shopify_plan.each do |shop|
6
+ DiscoApp::SynchroniseWebhooksJob.perform_later(shop)
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::Admin::ShopsControllerTest < ActionController::TestCase
4
+ include ActiveJob::TestHelper
5
+
6
+ def setup
7
+ ENV['ADMIN_APP_USERNAME'] = 'admin_app_username'
8
+ ENV['ADMIN_APP_PASSWORD'] = 'admin_app_password'
9
+ @routes = DiscoApp::Engine.routes
10
+ end
11
+
12
+ def teardown
13
+ ENV['ADMIN_APP_USERNAME'] = nil
14
+ ENV['ADMIN_APP_PASSWORD'] = nil
15
+ end
16
+
17
+ test 'can not access shops list without authorization' do
18
+ get(:index)
19
+ assert_response :unauthorized
20
+ end
21
+
22
+ test 'can not access shops list with incorrect username/password' do
23
+ authenticate('fakeuser', 'blah blah')
24
+ get(:index)
25
+ assert_response :unauthorized
26
+ end
27
+
28
+ test 'can not access shops list with blank username/password' do
29
+ authenticate('', '')
30
+ get(:index)
31
+ assert_response :unauthorized
32
+ end
33
+
34
+ test 'can not access shops list with blank username/password when env variables are blank' do
35
+ ENV['ADMIN_APP_USERNAME'] = ''
36
+ ENV['ADMIN_APP_PASSWORD'] = ''
37
+ authenticate('', '')
38
+ get(:index)
39
+ assert_response :unauthorized
40
+ end
41
+
42
+ test 'can access shops list with correct username/password' do
43
+ authenticate('admin_app_username', 'admin_app_password')
44
+ get(:index)
45
+ assert_response :ok
46
+ end
47
+
48
+ private
49
+
50
+ def authenticate(username, password)
51
+ request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(username, password)
52
+ end
53
+
54
+ end
@@ -0,0 +1,99 @@
1
+ require 'test_helper'
2
+
3
+ class DiscoApp::ChargesControllerTest < ActionController::TestCase
4
+ include ActiveJob::TestHelper
5
+ include DiscoApp::Test::ShopifyAPI
6
+
7
+ def setup
8
+ @shop = disco_app_shops(:widget_store)
9
+ @current_subscription = disco_app_subscriptions(:current_widget_store_subscription)
10
+ @new_charge = disco_app_recurring_application_charges(:new_widget_store_subscription_recurring_charge)
11
+ @routes = DiscoApp::Engine.routes
12
+ log_in_as(@shop)
13
+ @shop.installed!
14
+ end
15
+
16
+ def teardown
17
+ @shop = nil
18
+ @current_subscription = nil
19
+ WebMock.reset!
20
+ end
21
+
22
+ test 'non-logged in user is redirected to the login page' do
23
+ log_out
24
+ get(:new, subscription_id: @current_subscription)
25
+ assert_redirected_to ShopifyApp::Engine.routes.url_helpers.login_path
26
+ end
27
+
28
+ test 'logged-in, never installed user is redirected to the install page' do
29
+ @shop.never_installed!
30
+ get(:new, subscription_id: @current_subscription)
31
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.install_path
32
+ end
33
+
34
+ test 'user with paid-for current subscription can not access page' do
35
+ get(:new, subscription_id: @current_subscription)
36
+ assert_redirected_to Rails.application.routes.url_helpers.root_path
37
+ end
38
+
39
+ test 'user with unpaid current subscription can access page' do
40
+ @current_subscription.active_charge.destroy
41
+ get(:new, subscription_id: @current_subscription)
42
+ assert_response :ok
43
+ end
44
+
45
+ test 'user with unpaid current subscription can create new charge and is redirected to confirmation url' do
46
+ res = { "recurring_application_charge": { "name": "Basic",
47
+ "price": "9.99",
48
+ "trial_days": 14,
49
+ "return_url": /^https:\/\/test\.example\.com\/subscriptions\/304261385\/charges\/53297050(1|2)\/activate$/,
50
+ "test": true
51
+ } }
52
+ stub_request(:post, "#{@shop.admin_url}/recurring_application_charges.json")
53
+ .with(body: res
54
+ ).to_return(status: 201, body:api_fixture("widget_store/charges/create_second_recurring_application_charge_response").to_json)
55
+
56
+ @current_subscription.active_charge.destroy
57
+ post(:create, subscription_id: @current_subscription)
58
+ assert_redirected_to 'https://apple.myshopify.com/admin/charges/654381179/confirm_recurring_application_charge?signature=BAhpBHsQASc%3D--b2e90c6e4e94fbae15a464c566a31a1c23e6bffa'
59
+ end
60
+
61
+ test 'user trying to activate charge for invalid gets not found and hence 404' do
62
+ assert_raises ActiveRecord::RecordNotFound do
63
+ get(:activate, subscription_id: '123', id: '456', charge_id: '789')
64
+ end
65
+ end
66
+
67
+ test 'user trying to activate invalid charge for valid subscription gets redirected to new charge page for that subscription' do
68
+ @current_subscription.active_charge.destroy
69
+ get(:activate, subscription_id: @current_subscription, id: '456', charge_id: '789')
70
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.new_subscription_charge_path(@current_subscription)
71
+ end
72
+
73
+ test 'user trying to activate pending charge is redirected back to new charge page' do
74
+ stub_api_request(:get, "#{@shop.admin_url}/recurring_application_charges/654381179.json", 'widget_store/charges/get_pending_recurring_application_charge')
75
+
76
+ @current_subscription.active_charge.destroy
77
+ get(:activate, subscription_id: @current_subscription, id: @new_charge.id, charge_id: @new_charge.shopify_id)
78
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.new_subscription_charge_path(@current_subscription)
79
+ end
80
+
81
+ test 'user trying to activate declined charge is redirected back to new charge page' do
82
+ stub_api_request(:get, "#{@shop.admin_url}/recurring_application_charges/654381179.json", 'widget_store/charges/get_declined_recurring_application_charge')
83
+
84
+ @current_subscription.active_charge.destroy
85
+ get(:activate, subscription_id: @current_subscription, id: @new_charge.id, charge_id: @new_charge.shopify_id)
86
+ assert_redirected_to DiscoApp::Engine.routes.url_helpers.new_subscription_charge_path(@current_subscription)
87
+ end
88
+
89
+ test 'user trying to activate accepted charge succeeds and is redirected to the root page' do
90
+ stub_api_request(:get, "#{@shop.admin_url}/recurring_application_charges/654381179.json", 'widget_store/charges/get_accepted_recurring_application_charge')
91
+ stub_api_request(:post, "#{@shop.admin_url}/recurring_application_charges/654381179/activate.json", 'widget_store/charges/activate_recurring_application_charge')
92
+
93
+ @current_subscription.active_charge.destroy
94
+ get(:activate, subscription_id: @current_subscription, id: @new_charge.id, charge_id: @new_charge.shopify_id)
95
+ assert_equal @new_charge, @current_subscription.active_charge
96
+ assert_redirected_to Rails.application.routes.url_helpers.root_path
97
+ end
98
+
99
+ end