disco_app 0.15.2 → 0.18.1

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 (310) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -5
  3. data/app/clients/disco_app/api_client.rb +25 -19
  4. data/app/clients/disco_app/graphql_client.rb +85 -0
  5. data/app/controllers/disco_app/admin/app_settings_controller.rb +2 -0
  6. data/app/controllers/disco_app/admin/application_controller.rb +1 -0
  7. data/app/controllers/disco_app/admin/concerns/app_settings_controller.rb +2 -1
  8. data/app/controllers/disco_app/admin/concerns/authenticated_controller.rb +5 -3
  9. data/app/controllers/disco_app/admin/concerns/plans_controller.rb +3 -2
  10. data/app/controllers/disco_app/admin/concerns/shops_controller.rb +1 -0
  11. data/app/controllers/disco_app/admin/concerns/sources_controller.rb +2 -1
  12. data/app/controllers/disco_app/admin/concerns/subscriptions_controller.rb +3 -2
  13. data/app/controllers/disco_app/admin/plans_controller.rb +2 -0
  14. data/app/controllers/disco_app/admin/resources/shops_controller.rb +2 -0
  15. data/app/controllers/disco_app/admin/shops_controller.rb +2 -0
  16. data/app/controllers/disco_app/admin/sources_controller.rb +2 -0
  17. data/app/controllers/disco_app/admin/subscriptions_controller.rb +2 -0
  18. data/app/controllers/disco_app/charges_controller.rb +6 -7
  19. data/app/controllers/disco_app/concerns/app_proxy_controller.rb +6 -6
  20. data/app/controllers/disco_app/concerns/authenticated_controller.rb +26 -27
  21. data/app/controllers/disco_app/concerns/carrier_request_controller.rb +22 -11
  22. data/app/controllers/disco_app/concerns/user_authenticated_controller.rb +1 -0
  23. data/app/controllers/disco_app/concerns/webhooks_controller.rb +13 -12
  24. data/app/controllers/disco_app/flow/actions_controller.rb +9 -0
  25. data/app/controllers/disco_app/flow/concerns/actions_controller.rb +23 -0
  26. data/app/controllers/disco_app/flow/concerns/trigger_usage_controller.rb +29 -0
  27. data/app/controllers/disco_app/flow/concerns/verifies_flow_payload.rb +39 -0
  28. data/app/controllers/disco_app/flow/trigger_usage_controller.rb +9 -0
  29. data/app/controllers/disco_app/frame_controller.rb +0 -1
  30. data/app/controllers/disco_app/install_controller.rb +3 -6
  31. data/app/controllers/disco_app/subscriptions_controller.rb +12 -4
  32. data/app/controllers/disco_app/user_sessions_controller.rb +1 -0
  33. data/app/controllers/disco_app/webhooks_controller.rb +2 -0
  34. data/app/controllers/sessions_controller.rb +5 -6
  35. data/app/helpers/disco_app/application_helper.rb +7 -7
  36. data/app/jobs/disco_app/app_installed_job.rb +2 -0
  37. data/app/jobs/disco_app/app_uninstalled_job.rb +2 -0
  38. data/app/jobs/disco_app/concerns/app_installed_job.rb +2 -3
  39. data/app/jobs/disco_app/concerns/app_uninstalled_job.rb +2 -1
  40. data/app/jobs/disco_app/concerns/customers_data_request_job.rb +13 -0
  41. data/app/jobs/disco_app/concerns/customers_redact_job.rb +13 -0
  42. data/app/jobs/disco_app/concerns/render_asset_group_job.rb +1 -0
  43. data/app/jobs/disco_app/concerns/shop_redact_job.rb +13 -0
  44. data/app/jobs/disco_app/concerns/shop_update_job.rb +9 -2
  45. data/app/jobs/disco_app/concerns/subscription_changed_job.rb +2 -1
  46. data/app/jobs/disco_app/concerns/synchronise_carrier_service_job.rb +8 -7
  47. data/app/jobs/disco_app/concerns/synchronise_resources_job.rb +1 -0
  48. data/app/jobs/disco_app/concerns/synchronise_users_job.rb +6 -3
  49. data/app/jobs/disco_app/concerns/synchronise_webhooks_job.rb +24 -11
  50. data/app/jobs/disco_app/customers_data_request_job.rb +5 -0
  51. data/app/jobs/disco_app/customers_redact_job.rb +5 -0
  52. data/app/jobs/disco_app/flow/process_action_job.rb +11 -0
  53. data/app/jobs/disco_app/flow/process_trigger_job.rb +11 -0
  54. data/app/jobs/disco_app/render_asset_group_job.rb +2 -0
  55. data/app/jobs/disco_app/shop_job.rb +10 -10
  56. data/app/jobs/disco_app/shop_redact_job.rb +5 -0
  57. data/app/jobs/disco_app/shop_update_job.rb +2 -0
  58. data/app/jobs/disco_app/subscription_changed_job.rb +2 -0
  59. data/app/jobs/disco_app/synchronise_carrier_service_job.rb +2 -0
  60. data/app/jobs/disco_app/synchronise_resources_job.rb +2 -0
  61. data/app/jobs/disco_app/synchronise_users_job.rb +2 -0
  62. data/app/jobs/disco_app/synchronise_webhooks_job.rb +2 -0
  63. data/app/models/application_record.rb +2 -0
  64. data/app/models/disco_app/app_settings.rb +2 -0
  65. data/app/models/disco_app/application_charge.rb +1 -1
  66. data/app/models/disco_app/concerns/app_settings.rb +2 -0
  67. data/app/models/disco_app/concerns/can_be_liquified.rb +29 -14
  68. data/app/models/disco_app/concerns/has_metafields.rb +1 -2
  69. data/app/models/disco_app/concerns/plan.rb +3 -4
  70. data/app/models/disco_app/concerns/plan_code.rb +1 -2
  71. data/app/models/disco_app/concerns/renders_assets.rb +15 -21
  72. data/app/models/disco_app/concerns/shop.rb +20 -14
  73. data/app/models/disco_app/concerns/source.rb +2 -3
  74. data/app/models/disco_app/concerns/subscription.rb +3 -3
  75. data/app/models/disco_app/concerns/synchronises.rb +10 -15
  76. data/app/models/disco_app/concerns/taggable.rb +1 -0
  77. data/app/models/disco_app/concerns/user.rb +3 -2
  78. data/app/models/disco_app/flow/action.rb +9 -0
  79. data/app/models/disco_app/flow/concerns/action.rb +27 -0
  80. data/app/models/disco_app/flow/concerns/trigger.rb +28 -0
  81. data/app/models/disco_app/flow/concerns/trigger_usage.rb +17 -0
  82. data/app/models/disco_app/flow/trigger.rb +9 -0
  83. data/app/models/disco_app/flow/trigger_usage.rb +9 -0
  84. data/app/models/disco_app/plan.rb +2 -0
  85. data/app/models/disco_app/plan_code.rb +2 -0
  86. data/app/models/disco_app/session_storage.rb +5 -2
  87. data/app/models/disco_app/shop.rb +2 -0
  88. data/app/models/disco_app/source.rb +2 -0
  89. data/app/models/disco_app/subscription.rb +2 -0
  90. data/app/models/disco_app/user.rb +2 -0
  91. data/app/resources/disco_app/admin/resources/concerns/shop_resource.rb +12 -15
  92. data/app/resources/disco_app/admin/resources/shop_resource.rb +1 -0
  93. data/app/services/disco_app/carrier_request_service.rb +3 -3
  94. data/app/services/disco_app/charges_service.rb +26 -34
  95. data/app/services/disco_app/flow/create_action.rb +35 -0
  96. data/app/services/disco_app/flow/create_trigger.rb +34 -0
  97. data/app/services/disco_app/flow/process_action.rb +50 -0
  98. data/app/services/disco_app/flow/process_trigger.rb +72 -0
  99. data/app/services/disco_app/flow/update_trigger_usage.rb +42 -0
  100. data/app/services/disco_app/partner_app_service.rb +1 -1
  101. data/app/services/disco_app/proxy_service.rb +2 -2
  102. data/app/services/disco_app/request_validation_service.rb +2 -2
  103. data/app/services/disco_app/subscription_service.rb +60 -32
  104. data/app/services/disco_app/webhook_service.rb +9 -11
  105. data/app/views/layouts/admin.html.erb +1 -2
  106. data/app/views/layouts/application.html.erb +1 -2
  107. data/app/views/layouts/embedded_app.html.erb +2 -4
  108. data/app/views/layouts/embedded_app_modal.html.erb +2 -3
  109. data/app/views/shopify_app/sessions/new.html.erb +2 -4
  110. data/config/routes.rb +11 -3
  111. data/db/migrate/20150525000000_create_shops_if_not_existent.rb +80 -80
  112. data/db/migrate/20170315062548_create_disco_app_sources.rb +2 -0
  113. data/db/migrate/20170315062629_add_sources_to_shop_subscriptions.rb +3 -1
  114. data/db/migrate/20170327214540_create_disco_app_users.rb +2 -1
  115. data/db/migrate/20170606160751_fix_disco_app_users_index.rb +2 -0
  116. data/db/migrate/20181229100327_create_flow_actions_and_triggers.rb +32 -0
  117. data/db/migrate/20200405000000_create_flow_trigger_usages.rb +16 -0
  118. data/lib/disco_app/configuration.rb +12 -5
  119. data/lib/disco_app/constants.rb +4 -2
  120. data/lib/disco_app/engine.rb +1 -1
  121. data/lib/disco_app/session.rb +1 -0
  122. data/lib/disco_app/support/file_fixtures.rb +2 -1
  123. data/lib/disco_app/version.rb +3 -1
  124. data/lib/generators/disco_app/install/USAGE +5 -0
  125. data/lib/generators/disco_app/install/install_generator.rb +297 -0
  126. data/lib/generators/disco_app/{templates → install/templates}/assets/javascripts/application.js +0 -0
  127. data/lib/generators/disco_app/{templates → install/templates}/assets/javascripts/components.js +0 -0
  128. data/lib/generators/disco_app/{templates → install/templates}/assets/stylesheets/application.scss +0 -0
  129. data/lib/generators/disco_app/install/templates/config/appsignal.yml +12 -0
  130. data/lib/generators/disco_app/install/templates/config/cable.yml.tt +11 -0
  131. data/lib/generators/disco_app/{templates → install/templates}/config/database.yml.tt +6 -3
  132. data/lib/generators/disco_app/install/templates/config/environments/staging.rb +108 -0
  133. data/lib/generators/disco_app/{templates → install/templates}/config/puma.rb +0 -0
  134. data/lib/generators/disco_app/{templates → install/templates}/controllers/home_controller.rb +1 -0
  135. data/lib/generators/disco_app/{templates → install/templates}/initializers/disco_app.rb +5 -0
  136. data/lib/generators/disco_app/install/templates/initializers/session_store.rb +2 -0
  137. data/lib/generators/disco_app/install/templates/initializers/shopify_app.rb +11 -0
  138. data/lib/generators/disco_app/{templates → install/templates}/initializers/shopify_session_repository.rb +0 -0
  139. data/lib/generators/disco_app/install/templates/initializers/timber.rb +4 -0
  140. data/lib/generators/disco_app/{templates → install/templates}/root/.editorconfig +0 -0
  141. data/lib/generators/disco_app/{templates → install/templates}/root/.env +7 -0
  142. data/lib/generators/disco_app/{templates → install/templates}/root/.env.local +4 -0
  143. data/lib/generators/disco_app/{templates → install/templates}/root/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  144. data/lib/generators/disco_app/{templates → install/templates}/root/.gitignore +6 -0
  145. data/lib/generators/disco_app/install/templates/root/.rspec +1 -0
  146. data/lib/generators/disco_app/{templates → install/templates}/root/.rubocop.yml +315 -217
  147. data/lib/generators/disco_app/install/templates/root/.tool-versions +2 -0
  148. data/lib/generators/disco_app/{templates → install/templates}/root/CHECKS +0 -0
  149. data/lib/generators/disco_app/{templates → install/templates}/root/Procfile +0 -0
  150. data/lib/generators/disco_app/{templates → install/templates}/root/README.md +0 -0
  151. data/lib/generators/disco_app/install/templates/root/package.json.tt +17 -0
  152. data/lib/generators/disco_app/install/templates/spec/rails_helper.rb +40 -0
  153. data/lib/generators/disco_app/install/templates/spec/spec_helper.rb +24 -0
  154. data/lib/generators/disco_app/install/templates/spec/support/active_job.rb +13 -0
  155. data/lib/generators/disco_app/install/templates/spec/support/coveralls.rb +3 -0
  156. data/lib/generators/disco_app/install/templates/spec/support/database_cleaner.rb +17 -0
  157. data/lib/generators/disco_app/install/templates/spec/support/factory_bot.rb +3 -0
  158. data/lib/generators/disco_app/install/templates/spec/support/helpers/json_helper.rb +13 -0
  159. data/lib/generators/disco_app/install/templates/spec/support/shared_examples/a_synchronise_job.rb +12 -0
  160. data/lib/generators/disco_app/install/templates/spec/support/shoulda.rb +6 -0
  161. data/lib/generators/disco_app/install/templates/spec/support/vcr.rb +14 -0
  162. data/lib/generators/disco_app/install/templates/spec/support/webmock.rb +8 -0
  163. data/lib/generators/disco_app/{templates → install/templates}/views/home/index.html.erb +0 -0
  164. data/lib/generators/disco_app/react/USAGE +5 -0
  165. data/lib/generators/disco_app/react/react_generator.rb +108 -0
  166. data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/base_controller.rb +18 -0
  167. data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/home_controller.rb +10 -0
  168. data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/shops_controller.rb +11 -0
  169. data/lib/generators/disco_app/react/templates/app/controllers/embedded/api/users_controller.rb +11 -0
  170. data/lib/generators/disco_app/react/templates/app/controllers/embedded/home_controller.rb +13 -0
  171. data/lib/generators/disco_app/react/templates/app/models/api_response.rb +107 -0
  172. data/lib/generators/disco_app/react/templates/app/serializers/disco_app/shop_serializer.rb +13 -0
  173. data/lib/generators/disco_app/react/templates/app/serializers/disco_app/user_serializer.rb +13 -0
  174. data/lib/generators/disco_app/react/templates/app/serializers/empty_serializer.rb +5 -0
  175. data/lib/generators/disco_app/react/templates/app/serializers/error_serializer.rb +76 -0
  176. data/lib/generators/disco_app/react/templates/app/views/embedded/home/index.html.erb +12 -0
  177. data/lib/generators/disco_app/react/templates/app/views/layouts/embedded.html.erb +10 -0
  178. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/App.jsx +77 -0
  179. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/HomePage.jsx +34 -0
  180. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/EmbeddedPage.jsx +70 -0
  181. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/ErrorBanner.jsx +58 -0
  182. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/PaginationWrapper.jsx +10 -0
  183. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/Shared/ScrollToTop.jsx +23 -0
  184. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/components/withApi.jsx +125 -0
  185. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/index.jsx +39 -0
  186. data/lib/generators/disco_app/react/templates/app/webpack/javascripts/embedded/utils.js +19 -0
  187. data/lib/generators/disco_app/react/templates/app/webpack/packs/embedded.js +2 -0
  188. data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/banners.scss +7 -0
  189. data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/busy.scss +3 -0
  190. data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/index.scss +3 -0
  191. data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded/shared/pagination.scss +5 -0
  192. data/lib/generators/disco_app/react/templates/app/webpack/stylesheets/embedded.scss +2 -0
  193. data/lib/generators/disco_app/react/templates/config/initializers/mime_types.rb +13 -0
  194. data/lib/generators/disco_app/react/templates/config/initializers/omniauth.rb +27 -0
  195. data/lib/generators/disco_app/react/templates/config/initializers/version.rb.tt +7 -0
  196. data/lib/generators/disco_app/react/templates/config/webpack/staging.js +5 -0
  197. data/lib/generators/disco_app/react/templates/config/webpack/test.js +5 -0
  198. data/lib/generators/disco_app/react/templates/config/webpacker.yml +96 -0
  199. data/lib/generators/disco_app/react/templates/root/.eslintignore +5 -0
  200. data/lib/generators/disco_app/react/templates/root/.eslintrc +69 -0
  201. data/lib/generators/disco_app/react/templates/root/.prettierrc +3 -0
  202. data/lib/generators/disco_app/react/templates/root/VERSION +1 -0
  203. data/lib/generators/disco_app/react/templates/root/babel.config.js +72 -0
  204. data/lib/generators/disco_app/react/templates/root/package.json.tt +84 -0
  205. data/lib/generators/disco_app/react/templates/root/postcss.config.js +14 -0
  206. data/lib/tasks/api.rake +0 -2
  207. data/lib/tasks/carrier_service.rake +0 -2
  208. data/lib/tasks/database.rake +1 -1
  209. data/lib/tasks/sessions.rake +0 -2
  210. data/lib/tasks/shops.rake +0 -2
  211. data/lib/tasks/users.rake +0 -2
  212. data/lib/tasks/webhooks.rake +0 -2
  213. data/test/clients/disco_app/api_client_test.rb +3 -3
  214. data/test/controllers/disco_app/admin/shops_controller_test.rb +1 -0
  215. data/test/controllers/disco_app/charges_controller_test.rb +8 -9
  216. data/test/controllers/disco_app/flow/trigger_usage_controller_test.rb +41 -0
  217. data/test/controllers/disco_app/install_controller_test.rb +2 -1
  218. data/test/controllers/disco_app/subscriptions_controller_test.rb +2 -1
  219. data/test/controllers/disco_app/webhooks_controller_test.rb +1 -0
  220. data/test/controllers/home_controller_test.rb +1 -1
  221. data/test/disco_app_test.rb +3 -1
  222. data/test/dummy/Rakefile +1 -1
  223. data/test/dummy/app/assets/config/manifest.js +2 -0
  224. data/test/dummy/app/controllers/application_controller.rb +2 -0
  225. data/test/dummy/app/controllers/carrier_request_controller.rb +1 -0
  226. data/test/dummy/app/controllers/disco_app/admin/shops_controller.rb +1 -0
  227. data/test/dummy/app/controllers/home_controller.rb +1 -0
  228. data/test/dummy/app/controllers/proxy_controller.rb +1 -0
  229. data/test/dummy/app/javascript/packs/application.js +18 -0
  230. data/test/dummy/app/jobs/disco_app/app_installed_job.rb +2 -3
  231. data/test/dummy/app/jobs/disco_app/app_uninstalled_job.rb +1 -0
  232. data/test/dummy/app/models/application_record.rb +2 -0
  233. data/test/dummy/app/models/cart.rb +4 -3
  234. data/test/dummy/app/models/disco_app/shop.rb +4 -5
  235. data/test/dummy/app/models/js_configuration.rb +1 -0
  236. data/test/dummy/app/models/product.rb +3 -2
  237. data/test/dummy/app/models/widget_configuration.rb +1 -0
  238. data/test/dummy/babel.config.js +72 -0
  239. data/test/dummy/bin/bundle +1 -1
  240. data/test/dummy/bin/rails +1 -1
  241. data/test/dummy/bin/setup +8 -8
  242. data/test/dummy/bin/webpack +19 -0
  243. data/test/dummy/bin/webpack-dev-server +19 -0
  244. data/test/dummy/config/application.rb +4 -3
  245. data/test/dummy/config/boot.rb +2 -2
  246. data/test/dummy/config/database.yml +3 -0
  247. data/test/dummy/config/environment.rb +1 -1
  248. data/test/dummy/config/environments/staging.rb +85 -0
  249. data/test/dummy/config/initializers/disco_app.rb +8 -1
  250. data/test/dummy/config/initializers/omniauth.rb +3 -4
  251. data/test/dummy/config/initializers/session_store.rb +1 -1
  252. data/test/dummy/config/initializers/shopify_app.rb +1 -0
  253. data/test/dummy/config/routes.rb +0 -2
  254. data/test/dummy/config/secrets.yml +3 -0
  255. data/test/dummy/config/webpack/development.js +5 -0
  256. data/test/dummy/config/webpack/environment.js +3 -0
  257. data/test/dummy/config/webpack/production.js +5 -0
  258. data/test/dummy/config/webpack/test.js +5 -0
  259. data/test/dummy/config/webpacker.yml +95 -0
  260. data/test/dummy/db/migrate/20160307182229_create_products.rb +3 -1
  261. data/test/dummy/db/migrate/20160530160739_create_asset_models.rb +3 -1
  262. data/test/dummy/db/migrate/20161105054746_create_carts.rb +2 -1
  263. data/test/dummy/db/schema.rb +45 -6
  264. data/test/dummy/package.json +8 -0
  265. data/test/dummy/postcss.config.js +12 -0
  266. data/test/dummy/yarn.lock +7244 -0
  267. data/test/fixtures/api/subscriptions/valid_request.json +1 -1
  268. data/test/fixtures/api/widget_store/empty_webhooks.json +3 -0
  269. data/test/fixtures/api/widget_store/existing_webhooks.json +43 -0
  270. data/test/fixtures/disco_app/shops.yml +3 -0
  271. data/test/fixtures/webhooks/flow/trigger_usage.json +7 -0
  272. data/test/integration/synchronises_test.rb +2 -1
  273. data/test/jobs/disco_app/app_installed_job_test.rb +28 -9
  274. data/test/jobs/disco_app/app_uninstalled_job_test.rb +5 -2
  275. data/test/jobs/disco_app/send_subscription_job_test.rb +3 -2
  276. data/test/jobs/disco_app/synchronise_carrier_service_job_test.rb +1 -0
  277. data/test/jobs/disco_app/synchronise_users_job_test.rb +1 -0
  278. data/test/jobs/disco_app/synchronise_webhooks_job_test.rb +70 -13
  279. data/test/models/disco_app/can_be_liquified_test.rb +3 -1
  280. data/test/models/disco_app/has_metafields_test.rb +37 -18
  281. data/test/models/disco_app/renders_assets_test.rb +2 -1
  282. data/test/models/disco_app/session_test.rb +2 -2
  283. data/test/models/disco_app/shop_test.rb +1 -1
  284. data/test/services/disco_app/charges_service_test.rb +7 -8
  285. data/test/services/disco_app/flow/create_action_test.rb +51 -0
  286. data/test/services/disco_app/flow/create_trigger_test.rb +56 -0
  287. data/test/services/disco_app/flow/process_action_test.rb +68 -0
  288. data/test/services/disco_app/flow/process_trigger_test.rb +94 -0
  289. data/test/services/disco_app/flow/update_trigger_usage_test.rb +87 -0
  290. data/test/services/disco_app/subscription_service_test.rb +3 -2
  291. data/test/support/test_file_fixtures.rb +2 -2
  292. data/test/support/test_shopify_api.rb +1 -1
  293. data/test/test_helper.rb +10 -7
  294. data/test/vcr/flow_trigger_invalid_title.yml +35 -0
  295. data/test/vcr/flow_trigger_valid.yml +38 -0
  296. data/test/vcr/webhook_failure.yml +13 -13
  297. metadata +282 -148
  298. data/app/clients/disco_app/disco_api_error.rb +0 -2
  299. data/app/clients/disco_app/rollbar_client.rb +0 -53
  300. data/app/clients/disco_app/rollbar_client_error.rb +0 -2
  301. data/lib/generators/disco_app/USAGE +0 -5
  302. data/lib/generators/disco_app/disco_app_generator.rb +0 -236
  303. data/lib/generators/disco_app/templates/config/newrelic.yml +0 -26
  304. data/lib/generators/disco_app/templates/initializers/rollbar.rb +0 -23
  305. data/lib/generators/disco_app/templates/initializers/session_store.rb +0 -2
  306. data/lib/generators/disco_app/templates/initializers/shopify_app.rb +0 -6
  307. data/lib/generators/disco_app/templates/root/.codeclimate.yml +0 -7
  308. data/lib/generators/disco_app/templates/root/.ruby-version +0 -1
  309. data/lib/tasks/rollbar.rake +0 -24
  310. data/test/fixtures/api/widget_store/webhooks.json +0 -1
@@ -0,0 +1,2 @@
1
+ ruby 2.6.5
2
+ nodejs 13.7.0
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "<%= Rails.application.class.parent_name.underscore.dasherize %>",
3
+ "private": true,
4
+ "dependencies": {
5
+ "@rails/actioncable": "^6.0.0-alpha",
6
+ "@rails/activestorage": "^6.0.0-alpha",
7
+ "@rails/ujs": "^6.0.0-alpha",
8
+ "@rails/webpacker": "^4.0.7",
9
+ "react": "^16.11.0",
10
+ "react-dom": "^16.11.0",
11
+ "react_ujs": "^2.6.0",
12
+ "turbolinks": "^5.2.0"
13
+ },
14
+ "devDependencies": {
15
+ "webpack-dev-server": "^3.9.0"
16
+ }
17
+ }
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ ENV['RAILS_ENV'] ||= 'test'
3
+ require File.expand_path('../config/environment', __dir__)
4
+
5
+ abort('The Rails environment is running in production mode!') if Rails.env.production?
6
+
7
+ require 'rspec/rails'
8
+
9
+ # Add additional requires below this line. Rails is not loaded until this point!
10
+
11
+ # Requires supporting ruby files with custom matchers and macros, etc, in
12
+ # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
13
+ # run as spec files by default. This means that files in spec/support that end
14
+ # in _spec.rb will both be required and run as specs, causing the specs to be
15
+ # run twice. It is recommended that you do not name files matching this glob to
16
+ # end with _spec.rb. You can configure this pattern with the --pattern
17
+ # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
18
+ #
19
+ # The following line is provided for convenience purposes. It has the downside
20
+ # of increasing the boot-up time by auto-requiring all files in the support
21
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
22
+ # require only the support files necessary.
23
+ #
24
+ Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
25
+
26
+ # Checks for pending migrations and applies them before tests are run.
27
+ begin
28
+ ActiveRecord::Migration.maintain_test_schema!
29
+ rescue ActiveRecord::PendingMigrationError => e
30
+ puts e.to_s.strip
31
+ exit 1
32
+ end
33
+
34
+ RSpec.configure do |config|
35
+ config.filter_rails_from_backtrace!
36
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
37
+ config.infer_spec_type_from_file_location!
38
+ config.use_transactional_fixtures = false
39
+ config.include Helpers::JsonHelper
40
+ end
@@ -0,0 +1,24 @@
1
+ require 'support/coveralls'
2
+ require 'support/webmock'
3
+
4
+ RSpec.configure do |config|
5
+ config.expect_with :rspec do |expectations|
6
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
7
+ end
8
+
9
+ config.mock_with :rspec do |mocks|
10
+ mocks.verify_partial_doubles = true
11
+ end
12
+
13
+ config.default_formatter = 'doc' if config.files_to_run.one?
14
+ config.disable_monkey_patching!
15
+ config.example_status_persistence_file_path = 'spec/examples.txt'
16
+ config.filter_run_when_matching :focus
17
+ config.order = :random
18
+ config.shared_context_metadata_behavior = :apply_to_host_groups
19
+
20
+ config.filter_run focus: true
21
+ config.run_all_when_everything_filtered = true
22
+
23
+ Kernel.srand config.seed
24
+ end
@@ -0,0 +1,13 @@
1
+ require 'sidekiq/testing'
2
+
3
+ RSpec.configure do |config|
4
+ config.include ActiveJob::TestHelper
5
+
6
+ config.before(:all) do
7
+ Sidekiq::Testing.fake!
8
+ end
9
+
10
+ config.before(:each) do
11
+ Sidekiq::Worker.clear_all
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ require 'coveralls'
2
+
3
+ Coveralls.wear!('rails')
@@ -0,0 +1,17 @@
1
+ RSpec.configure do |config|
2
+ config.before(:suite) do
3
+ DatabaseCleaner.clean_with(:truncation)
4
+ end
5
+
6
+ config.before(:each) do
7
+ DatabaseCleaner.strategy = :transaction
8
+ end
9
+
10
+ config.before(:each) do
11
+ DatabaseCleaner.start
12
+ end
13
+
14
+ config.after(:each) do
15
+ DatabaseCleaner.clean
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.include FactoryBot::Syntax::Methods
3
+ end
@@ -0,0 +1,13 @@
1
+ module Helpers
2
+ module JsonHelper
3
+
4
+ # Return a JSON fixture as an indifferent hash.
5
+ def json_fixture(path, dir: 'json', parse: true)
6
+ filename = Rails.root.join('spec', 'fixtures', 'files', dir, "#{path}.json")
7
+ return File.read(filename) unless parse
8
+
9
+ HashWithIndifferentAccess.new(ActiveSupport::JSON.decode(File.read(filename)))
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ RSpec.shared_examples :a_synchronise_job do |model|
2
+ subject(:job) { described_class.perform_later(shop, data) }
3
+
4
+ let(:shop) { create(:shop) }
5
+ let(:data) { 'data' }
6
+
7
+ it "synchronises #{model}" do
8
+ expect(model).to receive(:synchronise).with(shop, data, any_args)
9
+
10
+ perform_enqueued_jobs { job }
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ Shoulda::Matchers.configure do |config|
2
+ config.integrate do |with|
3
+ with.test_framework :rspec
4
+ with.library :rails
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ VCR.configure do |config|
2
+ config.before_record do |interaction|
3
+ interaction.request.headers['X-Shopify-Access-Token'] = ['<REDACTED>']
4
+ interaction.request.headers['Authorization'] = ['<REDACTED>']
5
+ end
6
+ config.cassette_library_dir = 'spec/vcr'
7
+ config.configure_rspec_metadata!
8
+ config.default_cassette_options = {
9
+ decode_compressed_response: true,
10
+ match_requests_on: %i[method uri body],
11
+ record: :once
12
+ }
13
+ config.hook_into :webmock
14
+ end
@@ -0,0 +1,8 @@
1
+ require 'webmock/rspec'
2
+
3
+ RSpec.configure do |config|
4
+ config.before(:each) do
5
+ WebMock.reset!
6
+ WebMock.disable_net_connect!
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Generate boilerplate for a React-flavoured embedded app.
3
+
4
+ Example:
5
+ rails generate disco_app:react
@@ -0,0 +1,108 @@
1
+ module DiscoApp
2
+ module Generators
3
+ class ReactGenerator < Rails::Generators::Base
4
+
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ def prepare_application
8
+ copy_file 'root/VERSION', 'VERSION'
9
+ end
10
+
11
+ def configure_gemfile
12
+ gem 'fast_jsonapi'
13
+ gem 'multi_json'
14
+ gem 'oj'
15
+ gem 'olive_branch'
16
+ gem 'webpacker'
17
+ end
18
+
19
+ def bundle_install
20
+ Bundler.with_clean_env do
21
+ run 'bundle install'
22
+ end
23
+ end
24
+
25
+ def configure_application
26
+ application 'config.middleware.use OliveBranch::Middleware'
27
+ application '# Camel-case to underscore transformation for JSON requests.'
28
+
29
+ copy_file 'config/initializers/mime_types.rb'
30
+ copy_file 'config/initializers/omniauth.rb'
31
+ template 'config/initializers/version.rb.tt', 'config/initializers/version.rb'
32
+
33
+ %w[.env .env.local].each do |file|
34
+ append_to_file file, 'BUGSNAG_API_KEY=00000000'
35
+ end
36
+ end
37
+
38
+ def update_routes
39
+ routes = <<-ROUTES.gsub(/^ {8}/, '')
40
+ # Embedded React routes.
41
+ root to: 'embedded/home#index'
42
+
43
+ # Embedded API.
44
+ namespace :embedded do
45
+ namespace :api, constraints: { format: :json }, defaults: { format: :json } do
46
+ resource :shop, only: [:show]
47
+
48
+ resources :users, only: [] do
49
+ get :current, on: :collection
50
+ end
51
+ end
52
+ end
53
+ ROUTES
54
+
55
+ route routes
56
+
57
+ comment_lines 'config/routes.rb', "root to: 'home#index'"
58
+ end
59
+
60
+ def install_webpacker
61
+ rake 'webpacker:install'
62
+ end
63
+
64
+ def configure_webpack
65
+ %w[.eslintignore .eslintrc .prettierrc babel.config.js postcss.config.js].each do |file|
66
+ copy_file "root/#{file}", file
67
+ end
68
+
69
+ template 'root/package.json.tt', 'package.json'
70
+
71
+ copy_file 'config/webpacker.yml'
72
+ copy_file 'config/webpack/staging.js'
73
+ copy_file 'config/webpack/test.js'
74
+
75
+ run "if [ -d 'app/javascript' ]; then mv -f app/javascript app/webpack; fi"
76
+ end
77
+
78
+ def yarn_install
79
+ run 'yarn install'
80
+ end
81
+
82
+ def configure_api
83
+ directory 'app/controllers/embedded'
84
+ end
85
+
86
+ def configure_views
87
+ directory 'app/views/embedded'
88
+ copy_file 'app/views/layouts/embedded.html.erb'
89
+ end
90
+
91
+ def configure_serializers
92
+ directory 'app/serializers'
93
+ end
94
+
95
+ def configure_api_response
96
+ copy_file 'app/models/api_response.rb'
97
+ end
98
+
99
+ def configure_react
100
+ directory 'app/webpack/javascripts'
101
+ directory 'app/webpack/stylesheets'
102
+ copy_file 'app/webpack/packs/embedded.js'
103
+ remove_file 'app/webpack/packs/application.js'
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,18 @@
1
+ module Embedded
2
+ module Api
3
+ class BaseController < ApplicationController
4
+
5
+ include DiscoApp::Concerns::AuthenticatedController
6
+ include DiscoApp::Concerns::UserAuthenticatedController
7
+
8
+ rescue_from ActiveRecord::RecordInvalid, with: :unprocessable_entity
9
+
10
+ private
11
+
12
+ def unprocessable_entity(exception)
13
+ render json: ApiResponse.serialize(exception.record.errors), status: :unprocessable_entity
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ module Embedded
2
+ module Api
3
+ class HomeController < BaseController
4
+
5
+ def show
6
+ end
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Embedded
2
+ module Api
3
+ class ShopsController < BaseController
4
+
5
+ def show
6
+ render json: ApiResponse.serialize(@shop)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Embedded
2
+ module Api
3
+ class UsersController < BaseController
4
+
5
+ def current
6
+ render json: ApiResponse.serialize(@user)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Embedded
2
+ class HomeController < ApplicationController
3
+
4
+ include DiscoApp::Concerns::AuthenticatedController
5
+ include DiscoApp::Concerns::UserAuthenticatedController
6
+
7
+ layout 'embedded'
8
+
9
+ def index
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApiResponse
4
+
5
+ EMPTY_SERIALIZER = 'Empty'
6
+ ERROR_SERIALIZER = 'Error'
7
+ SERIALIZER_SUFFIX = 'Serializer'
8
+ SENSITIVE_REQUEST_PARAMS = ['timestamp', 'signature'].freeze
9
+
10
+ def initialize(result, custom_serializer = nil)
11
+ @result = result
12
+ @custom_serializer = custom_serializer
13
+ end
14
+
15
+ def serialize(options = {})
16
+ request = options.delete(:request)
17
+
18
+ serializer.new(
19
+ result, options.merge(collection_options(request))
20
+ ).serializable_hash
21
+ end
22
+
23
+ def self.serialize(result, options = {})
24
+ serializer = options.delete(:serializer)
25
+
26
+ new(result, serializer).serialize(options)
27
+ end
28
+
29
+ private
30
+
31
+ attr_accessor :result, :custom_serializer
32
+
33
+ def array?
34
+ result.is_a?(Array)
35
+ end
36
+
37
+ def collection?
38
+ result.is_a?(ActiveRecord::Relation)
39
+ end
40
+
41
+ def error?
42
+ [
43
+ result.is_a?(ActiveModel::Errors),
44
+ result.is_a?(ActiveResource::Errors),
45
+ result.is_a?(StandardError),
46
+ result.is_a?(String)
47
+ ].any?
48
+ end
49
+
50
+ def empty?
51
+ (array? || collection?) && result.empty?
52
+ end
53
+
54
+ def resource?
55
+ !array && !collection? && !error?
56
+ end
57
+
58
+ def resource_type
59
+ return custom_serializer.to_s.classify if custom_serializer
60
+ return ERROR_SERIALIZER if error?
61
+ return EMPTY_SERIALIZER if empty?
62
+ return result.first.class.name if array?
63
+ return result.class.to_s.deconstantize if collection?
64
+
65
+ result.class.name
66
+ end
67
+
68
+ def serializer
69
+ "#{resource_type}#{SERIALIZER_SUFFIX}".constantize
70
+ end
71
+
72
+ def collection_options(request = nil)
73
+ options = {}
74
+
75
+ return options if error?
76
+
77
+ options[:is_collection] = array? || collection?
78
+
79
+ if collection? && result.respond_to?(:total_count)
80
+ options[:meta] = {
81
+ page_size: result.limit_value,
82
+ total_count: result.total_count,
83
+ total_pages: result.total_pages
84
+ }
85
+
86
+ options[:links] = {
87
+ prev: link(result.prev_page, request),
88
+ next: link(result.next_page, request)
89
+ }
90
+ end
91
+
92
+ options
93
+ end
94
+
95
+ def link(page, request)
96
+ return page if page.blank? || request.blank?
97
+
98
+ uri = URI.parse(request)
99
+ params = Rack::Utils.parse_query(uri.query)
100
+ params.delete_if{ |key| SENSITIVE_REQUEST_PARAMS.include?(key) }
101
+ params['page[number]'] = page
102
+ parsed_params = params.map{ |key, value| "#{key}=#{value}" }.join('&')
103
+
104
+ "#{uri.scheme}:://#{uri.host}#{uri.path}?#{parsed_params}"
105
+ end
106
+
107
+ end
@@ -0,0 +1,13 @@
1
+ module DiscoApp
2
+ class ShopSerializer
3
+
4
+ include FastJsonapi::ObjectSerializer
5
+
6
+ attributes :id, :name, :shopify_url
7
+
8
+ attribute :time_zone do |shop|
9
+ shop.time_zone.tzinfo.name
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module DiscoApp
2
+ class UserSerializer
3
+
4
+ include FastJsonapi::ObjectSerializer
5
+
6
+ attributes :email, :first_name, :id, :last_name
7
+
8
+ attribute :initials do |user|
9
+ [user.first_name, user.last_name].compact.map(&:first).join
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class EmptySerializer
2
+
3
+ include FastJsonapi::ObjectSerializer
4
+
5
+ end
@@ -0,0 +1,76 @@
1
+ class ErrorSerializer
2
+
3
+ attr_reader :errors, :source, :title
4
+
5
+ def initialize(errors, source: nil, title: nil)
6
+ @errors = errors
7
+ @source = source
8
+ @title = title
9
+ end
10
+
11
+ def serialized_json
12
+ serializable_hash.to_json
13
+ end
14
+
15
+ def serializable_hash
16
+ {
17
+ errors: formatted_errors
18
+ }
19
+ end
20
+
21
+ private
22
+
23
+ def formatted_errors
24
+ return errors_from_exception if exception_error?
25
+ return errors_from_string if string_error?
26
+
27
+ errors_from_active_model
28
+ end
29
+
30
+ def errors_from_active_model
31
+ error_array = []
32
+
33
+ errors.keys.each do |field|
34
+ errors.full_messages_for(field).each do |error|
35
+ error_array << {
36
+ source: { pointer: "/data/attributes/#{field}" },
37
+ title: title || 'Unprocessable entity',
38
+ detail: error
39
+ }
40
+ end
41
+ end
42
+
43
+ error_array
44
+ end
45
+
46
+ def errors_from_exception
47
+ error = {
48
+ title: title || errors.class.name.demodulize || 'Unknown error',
49
+ detail: errors.message
50
+ }
51
+
52
+ error[:source] = { pointer: source } if source
53
+
54
+ [error]
55
+ end
56
+
57
+ def errors_from_string
58
+ error = {
59
+ title: title || 'Unknown error',
60
+ detail: errors
61
+ }
62
+
63
+ error[:source] = { pointer: source } if source
64
+
65
+ [error]
66
+ end
67
+
68
+ def exception_error?
69
+ errors.is_a?(StandardError)
70
+ end
71
+
72
+ def string_error?
73
+ errors.is_a?(String)
74
+ end
75
+
76
+ end
@@ -0,0 +1,12 @@
1
+ <div
2
+ id="app"
3
+ data-api-key="<%= ShopifyApp.configuration.api_key %>"
4
+ data-bugsnag-api-key="<%= ENV['BUGSNAG_API_KEY'] %>"
5
+ data-debug="<%= Rails.env.development? ? 'true' : 'false' %>"
6
+ data-environment="<%= Rails.env %>"
7
+ data-force-redirect="<%= Rails.env.development? ? 'false' : 'true' %>"
8
+ data-shop-origin="<%= @shop_session&.url %>"
9
+ data-version="<%= Rails.application.class::VERSION %>"
10
+ ></div>
11
+ <%= javascript_pack_tag 'embedded' %>
12
+ <%= stylesheet_pack_tag 'embedded' %>
@@ -0,0 +1,10 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= ENV['SHOPIFY_APP_NAME'] %></title>
5
+ <%= csrf_meta_tags %>
6
+ </head>
7
+ <body>
8
+ <%= yield %>
9
+ </body>
10
+ </html>