shopify_app 7.2.0 → 8.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +5 -5
  2. data/.babelrc +5 -0
  3. data/.github/CODEOWNERS +1 -0
  4. data/{ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md} +0 -0
  5. data/.github/probots.yml +2 -0
  6. data/.gitignore +5 -0
  7. data/.nvmrc +1 -0
  8. data/.rubocop.yml +10 -0
  9. data/.ruby-version +1 -0
  10. data/.travis.yml +24 -12
  11. data/CHANGELOG.md +151 -0
  12. data/Gemfile +2 -0
  13. data/README.md +167 -68
  14. data/app/assets/images/storage_access.svg +2 -0
  15. data/app/assets/javascripts/shopify_app/enable_cookies.js +3 -0
  16. data/app/assets/javascripts/shopify_app/itp_helper.js +40 -0
  17. data/app/assets/javascripts/shopify_app/partition_cookies.js +7 -0
  18. data/app/assets/javascripts/shopify_app/redirect.js +33 -0
  19. data/app/assets/javascripts/shopify_app/request_storage_access.js +3 -0
  20. data/app/assets/javascripts/shopify_app/storage_access.js +121 -0
  21. data/app/assets/javascripts/shopify_app/storage_access_redirect.js +17 -0
  22. data/app/assets/javascripts/shopify_app/top_level.js +2 -0
  23. data/app/assets/javascripts/shopify_app/top_level_interaction.js +11 -0
  24. data/app/controllers/shopify_app/authenticated_controller.rb +5 -2
  25. data/app/controllers/shopify_app/callback_controller.rb +92 -0
  26. data/app/controllers/shopify_app/sessions_controller.rb +120 -2
  27. data/app/controllers/shopify_app/webhooks_controller.rb +11 -3
  28. data/app/views/shopify_app/partials/_button_styles.html.erb +104 -0
  29. data/app/views/shopify_app/partials/_card_styles.html.erb +33 -0
  30. data/app/views/shopify_app/partials/_empty_state_styles.html.erb +129 -0
  31. data/app/views/shopify_app/partials/_layout_styles.html.erb +167 -0
  32. data/app/views/shopify_app/partials/_typography_styles.html.erb +35 -0
  33. data/app/views/shopify_app/sessions/enable_cookies.html.erb +59 -0
  34. data/app/views/shopify_app/sessions/new.html.erb +88 -60
  35. data/app/views/shopify_app/sessions/request_storage_access.html.erb +67 -0
  36. data/app/views/shopify_app/sessions/top_level_interaction.html.erb +63 -0
  37. data/app/views/shopify_app/shared/redirect.html.erb +22 -0
  38. data/config/locales/de.yml +22 -0
  39. data/config/locales/en.yml +12 -1
  40. data/config/locales/es.yml +21 -3
  41. data/config/locales/fr.yml +23 -0
  42. data/config/locales/it.yml +22 -0
  43. data/config/locales/ja.yml +17 -0
  44. data/config/locales/nl.yml +21 -0
  45. data/config/locales/pt-BR.yml +22 -0
  46. data/config/locales/zh-CN.yml +16 -0
  47. data/config/locales/zh-TW.yml +17 -0
  48. data/config/routes.rb +11 -1
  49. data/{QUICKSTART.md → docs/Quickstart.md} +26 -23
  50. data/docs/Releasing.md +18 -0
  51. data/docs/Troubleshooting.md +16 -0
  52. data/karma.conf.js +43 -0
  53. data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +45 -0
  54. data/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb +10 -0
  55. data/lib/generators/shopify_app/home_controller/templates/home_controller.rb +1 -0
  56. data/lib/generators/shopify_app/home_controller/templates/index.html.erb +14 -0
  57. data/lib/generators/shopify_app/home_controller/templates/shopify_app_ready_script.html.erb +1 -5
  58. data/lib/generators/shopify_app/install/install_generator.rb +10 -16
  59. data/lib/generators/shopify_app/install/templates/_flash_messages.html.erb +13 -9
  60. data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +1 -1
  61. data/lib/generators/shopify_app/install/templates/shopify_app.rb +5 -3
  62. data/lib/generators/shopify_app/install/templates/shopify_provider.rb +19 -4
  63. data/lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb +16 -0
  64. data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token.rake +17 -0
  65. data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb +42 -0
  66. data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +5 -9
  67. data/lib/generators/shopify_app/shop_model/templates/db/migrate/{create_shops.rb → create_shops.erb} +1 -1
  68. data/lib/generators/shopify_app/shop_model/templates/shop.rb +0 -1
  69. data/lib/shopify_app/configuration.rb +27 -8
  70. data/lib/shopify_app/{app_proxy_verification.rb → controller_concerns/app_proxy_verification.rb} +2 -7
  71. data/lib/shopify_app/controller_concerns/embedded_app.rb +19 -0
  72. data/lib/shopify_app/controller_concerns/itp.rb +45 -0
  73. data/lib/shopify_app/controller_concerns/localization.rb +22 -0
  74. data/lib/shopify_app/controller_concerns/login_protection.rb +135 -0
  75. data/lib/shopify_app/{webhook_verification.rb → controller_concerns/webhook_verification.rb} +11 -12
  76. data/lib/shopify_app/engine.rb +10 -0
  77. data/lib/shopify_app/{scripttags_manager_job.rb → jobs/scripttags_manager_job.rb} +2 -2
  78. data/lib/shopify_app/{webhooks_manager_job.rb → jobs/webhooks_manager_job.rb} +0 -0
  79. data/lib/shopify_app/{scripttags_manager.rb → managers/scripttags_manager.rb} +24 -8
  80. data/lib/shopify_app/{webhooks_manager.rb → managers/webhooks_manager.rb} +1 -1
  81. data/lib/shopify_app/session/in_memory_session_store.rb +27 -0
  82. data/lib/shopify_app/{shopify_session_repository.rb → session/session_repository.rb} +0 -0
  83. data/lib/shopify_app/{session_storage.rb → session/session_storage.rb} +9 -0
  84. data/lib/shopify_app/utils.rb +2 -2
  85. data/lib/shopify_app/version.rb +1 -1
  86. data/lib/shopify_app.rb +21 -16
  87. data/package-lock.json +23 -0
  88. data/package.json +28 -0
  89. data/service.yml +7 -0
  90. data/shipit.rubygems.yml +2 -0
  91. data/shopify_app.gemspec +6 -5
  92. data/translation.yml +7 -0
  93. data/webpack.config.js +24 -0
  94. data/yarn.lock +4594 -0
  95. metadata +92 -35
  96. data/Gemfile.rails50 +0 -5
  97. data/Gemfile.ruby22 +0 -6
  98. data/Gemfile.ruby22.rails50 +0 -9
  99. data/RELEASING +0 -13
  100. data/lib/generators/shopify_app/install/templates/shopify_session_repository.rb +0 -23
  101. data/lib/generators/shopify_app/shop_model/templates/shopify_session_repository.rb +0 -7
  102. data/lib/shopify_app/in_memory_session_store.rb +0 -25
  103. data/lib/shopify_app/login_protection.rb +0 -103
  104. data/lib/shopify_app/sessions_concern.rb +0 -101
  105. data/lib/shopify_app/shop.rb +0 -15
@@ -0,0 +1,23 @@
1
+ ---
2
+ fr:
3
+ logged_out: Vous êtes déconnecté(e)
4
+ could_not_log_in: Impossible de se connecter à la boutique Shopify
5
+ invalid_shop_url: Url invalide
6
+ enable_cookies_heading: Activer les cookies de %{app}
7
+ enable_cookies_body: Vous devez manuellement activer les cookies dans ce navigateur
8
+ pour utiliser %{app} dans Shopify.
9
+ enable_cookies_footer: Les cookies permettent à l'application de vous authentifier
10
+ en stockant temporairement vos préférences et informations personnelles. Celles-ci
11
+ expirent après 30 jours.
12
+ enable_cookies_action: Activer les cookies
13
+ top_level_interaction_heading: Votre navigateur doit s'authentifier %{app}
14
+ top_level_interaction_body: Votre navigateur nécessite des applications tierces
15
+ telles que %{app} pour vous demander l'accès aux cookies avant que Shopify ne
16
+ puisse l'ouvrir pour vous.
17
+ top_level_interaction_action: Continuer
18
+ request_storage_access_heading: "%{app} a besoin d'accéder aux cookies"
19
+ request_storage_access_body: Cela permet à l'application de vous authentifier en
20
+ stockant temporairement vos informations personnelles. Cliquez pour continuer
21
+ et autorisez les cookies à utiliser l'application.
22
+ request_storage_access_footer: Les cookies expirent après 30 jours.
23
+ request_storage_access_action: Continuer
@@ -0,0 +1,22 @@
1
+ ---
2
+ it:
3
+ logged_out: Disconnessione effettuata correttamente
4
+ could_not_log_in: Impossibile accedere al negozio Shopify
5
+ invalid_shop_url: Dominio negozio non valido
6
+ enable_cookies_heading: Abilita i cookie di %{app}
7
+ enable_cookies_body: Devi abilitare manualmente i cookie in questo browser per poter
8
+ utilizzare %{app} da Shopify.
9
+ enable_cookies_footer: I cookie consentono all'app di autenticarti memorizzando
10
+ temporaneamente le tue preferenze e informazioni personali. Scadono dopo 30 giorni.
11
+ enable_cookies_action: Abilita i cookie
12
+ top_level_interaction_heading: Il tuo browser deve autenticare %{app}
13
+ top_level_interaction_body: Il tuo browser richiede che app di terze parti come
14
+ %{app} ti chiedano l'accesso ai cookie prima dell'apertura automatica da parte
15
+ di Shopify.
16
+ top_level_interaction_action: Continua
17
+ request_storage_access_heading: "%{app} deve accedere ai cookie"
18
+ request_storage_access_body: L'app potrà così autenticarti memorizzando temporaneamente
19
+ le tue informazioni personali. Clicca su Continua e consenti ai cookie di utilizzare
20
+ l'app.
21
+ request_storage_access_footer: I cookie scadono dopo 30 giorni.
22
+ request_storage_access_action: Continua
@@ -0,0 +1,17 @@
1
+ ---
2
+ ja:
3
+ logged_out: ログインに成功しました
4
+ could_not_log_in: Shopifyストアにログインできませんでした
5
+ invalid_shop_url: ショップのドメインが無効です
6
+ enable_cookies_heading: "%{app}からのCookieを有効にする"
7
+ enable_cookies_body: Shopifyで%{app}を使用できるようにするためには、このブラウザのCookieを手動で有効にする必要があります。
8
+ enable_cookies_footer: Cookieを使用すると、各種設定や個人情報を一時的に保存することで、アプリ認証を受けることができます。30日後に有効期限が切れます。
9
+ enable_cookies_action: Cookieを有効にする
10
+ top_level_interaction_heading: お使いのブラウザを更新する必要があります%{app}
11
+ top_level_interaction_body: Shopifyがアプリを開けるように、ブラウザーはCookie にアクセスするための%{app}のような外部アプリが必要です。
12
+ top_level_interaction_action: 続ける
13
+ request_storage_access_heading: "%{app}クッキーにアクセスする必要がある"
14
+ request_storage_access_body: Cookieを使用すると、個人情報を一時的に保存することで、アプリ認証を受けることができます。[続行]
15
+ をクリックして、Cookieでアプリを使用できるようにします。
16
+ request_storage_access_footer: Cookieは30日後に有効期限が切れます。
17
+ request_storage_access_action: 続ける
@@ -0,0 +1,21 @@
1
+ ---
2
+ nl:
3
+ logged_out: U bent afgemeld
4
+ could_not_log_in: Kon niet aanmelden bij Shopify-winkel
5
+ invalid_shop_url: Ongeldig winkeldomein
6
+ enable_cookies_heading: Schakel cookies in van %{app}
7
+ enable_cookies_body: U moet cookies in deze browser handmatig inschakelen om %{app}
8
+ binnen Shopify te gebruiken.
9
+ enable_cookies_footer: Met cookies kan de app u verifiëren door uw voorkeuren en
10
+ persoonlijke informatie tijdelijk op te slaan. Ze vervallen na 30 dagen.
11
+ enable_cookies_action: Schakel cookies in
12
+ top_level_interaction_heading: Uw browser moet %{app} verifiëren
13
+ top_level_interaction_body: Uw browser heeft apps van derden nodig zoals %{app}
14
+ om u toegang te vragen tot cookies voordat Shopify het voor u kan openen.
15
+ top_level_interaction_action: Doorgaan
16
+ request_storage_access_heading: "%{app} heeft toegang tot cookies nodig"
17
+ request_storage_access_body: Hiermee kan de app u verifiëren door uw persoonlijke
18
+ gegevens tijdelijk op te slaan. Klik op Doorgaan en sta cookies toe om de app
19
+ te gebruiken.
20
+ request_storage_access_footer: Cookies verlopen na 30 dagen.
21
+ request_storage_access_action: Doorgaan
@@ -0,0 +1,22 @@
1
+ ---
2
+ pt-BR:
3
+ logged_out: Você saiu com sucesso
4
+ could_not_log_in: Não foi possível fazer login na Shopify store
5
+ invalid_shop_url: Domínio de loja inválido
6
+ enable_cookies_heading: Ativar cookies de %{app}
7
+ enable_cookies_body: Você deve ativar manualmente os cookies neste navegador para
8
+ usar %{app} dentro da Shopify.
9
+ enable_cookies_footer: Os cookies permitem que o aplicativo o autentique armazenando
10
+ temporariamente suas preferências e informações pessoais. Eles expiram depois
11
+ de 30 dias.
12
+ enable_cookies_action: Ativar cookies
13
+ top_level_interaction_heading: Seu navegador precisa autenticar %{app}
14
+ top_level_interaction_body: Seu navegador exige que apps de terceiros como o %{app}
15
+ consultem você sobre o acesso a cookies antes da Shopify abri-los.
16
+ top_level_interaction_action: Continuar
17
+ request_storage_access_heading: "%{app} precisa acessar cookies"
18
+ request_storage_access_body: Isso permite que o app autentique você armazenando
19
+ temporariamente seus dados pessoais. Clique em continuar e permita os cookies
20
+ para usar o app.
21
+ request_storage_access_footer: Os cookies expiram depois de 30 dias.
22
+ request_storage_access_action: Continuar
@@ -0,0 +1,16 @@
1
+ ---
2
+ zh-CN:
3
+ logged_out: 已成功注销
4
+ could_not_log_in: 无法登录到 Shopify 店铺
5
+ invalid_shop_url: 商店域无效
6
+ enable_cookies_heading: 从 %{app} 启用 Cookie
7
+ enable_cookies_body: 您必须在此浏览器中手动启用 Cookie 才能在 Shopify 中使用 %{app}。
8
+ enable_cookies_footer: Cookie 使此应用能够通过暂时存储您的首选项和个人信息来验证您的身份。这些信息将在 30 天后过期。
9
+ enable_cookies_action: 启用 Cookie
10
+ top_level_interaction_heading: 您的浏览器需要对 %{app} 进行验证
11
+ top_level_interaction_body: 您的浏览器要求类似 %{app} 的第三方应用向您请求访问 Cookie,之后 Shopify 才能为您打开它。
12
+ top_level_interaction_action: 继续
13
+ request_storage_access_heading: "%{app} 需要访问 Cookie"
14
+ request_storage_access_body: 这使此应用能够通过暂时存储您的个人信息来验证您的身份。单击继续并启用 Cookie 以使用此应用。
15
+ request_storage_access_footer: Cookie 将在 30 天后过期。
16
+ request_storage_access_action: 继续
@@ -0,0 +1,17 @@
1
+ ---
2
+ zh-TW:
3
+ logged_out: 登出成功
4
+ could_not_log_in: 無法登入 Shopify 商店
5
+ invalid_shop_url: 商店網域無效
6
+ enable_cookies_heading: 啟用 %{app} 的 Cookie
7
+ enable_cookies_body: 您必須在此瀏覽器中手動啟用 Cookie,才能夠在 Shopify 使用 %{app}。
8
+ enable_cookies_footer: Cookie 可讓應用程式暫時儲存您的偏好設定和個人資訊,藉此驗證您的身分,這些資料會在 30 天後失效。
9
+ enable_cookies_action: 啟用 Cookie
10
+ top_level_interaction_heading: 您的瀏覽器需要驗證 %{app}
11
+ top_level_interaction_body: 您的瀏覽器會要求第三方應用程式 (例如:%{app}) 向您請求 Cookie 的存取權限,然後才讓 Shopify
12
+ 為您開啟此應用程式。
13
+ top_level_interaction_action: 繼續
14
+ request_storage_access_heading: "%{app} 需要 Cookie 存取權限"
15
+ request_storage_access_body: Cookie 可讓應用程式暫時儲存您的個人資訊,藉此驗證您的身分。按一下繼續並允許 Cookie 使用此應用程式。
16
+ request_storage_access_footer: Cookie 將於 30 天後失效。
17
+ request_storage_access_action: 繼續
data/config/routes.rb CHANGED
@@ -2,10 +2,20 @@ ShopifyApp::Engine.routes.draw do
2
2
  controller :sessions do
3
3
  get 'login' => :new, :as => :login
4
4
  post 'login' => :create, :as => :authenticate
5
- get 'auth/shopify/callback' => :callback
5
+ get 'enable_cookies' => :enable_cookies, :as => :enable_cookies
6
+ get 'top_level_interaction' =>
7
+ :top_level_interaction,
8
+ :as => :top_level_interaction
9
+ get 'granted_storage_access' =>
10
+ :granted_storage_access,
11
+ :as => :granted_storage_access
6
12
  get 'logout' => :destroy, :as => :logout
7
13
  end
8
14
 
15
+ controller :callback do
16
+ get 'auth/shopify/callback' => :callback
17
+ end
18
+
9
19
  namespace :webhooks do
10
20
  post ':type' => :receive
11
21
  end
@@ -6,12 +6,12 @@ Build and deploy a new Shopify App to Heroku in minutes
6
6
  1. New Rails App (with postgres)
7
7
  --------------------------------
8
8
 
9
- ```
10
- rails new test-app --database=postgresql
11
- cd test-app
12
- git init
13
- git add .
14
- git commit -m 'new rails app'
9
+ ```sh
10
+ $ rails new test-app --database=postgresql
11
+ $ cd test-app
12
+ $ git init
13
+ $ git add .
14
+ $ git commit -m 'new rails app'
15
15
  ```
16
16
 
17
17
  2. Create a new Heroku app
@@ -20,17 +20,17 @@ git commit -m 'new rails app'
20
20
  The next step is to create a new heroku app. Pull up your heroku dashboard and make a new app!
21
21
 
22
22
  cli:
23
+ ```sh
24
+ $ heroku create name
25
+ $ heroku git:remote -a name
23
26
  ```
24
- heroku create name
25
- heroku git:remote -a name
26
- ```
27
27
 
28
28
  now we need to let git know where the remote server is so we'll be able to deploy later
29
29
 
30
30
  web:
31
- ```
32
- https://dashboard.heroku.com/new
33
- git remote add heroku git@heroku.com:appinfive.git
31
+ ```sh
32
+ # https://dashboard.heroku.com/new
33
+ $ git remote add heroku git@heroku.com:appinfive.git
34
34
  ```
35
35
 
36
36
  3. Create a new App in the partners area
@@ -43,28 +43,31 @@ git remote add heroku git@heroku.com:appinfive.git
43
43
 
44
44
  4. Add ShopifyApp to gemfile
45
45
  ----------------------------
46
- ```
46
+ ```sh
47
47
  $ echo "gem 'shopify_app'" >> Gemfile
48
-
49
- bundle install
48
+ $ bundle install
50
49
  ```
51
50
 
52
51
  Note - its recommended to use the latest released version. Check the git tags to see the latest release and then add it to your Gemfile e.g `gem 'shopify_app', '~> 7.0.0'`
53
52
 
54
53
  5. Run the ShopifyApp generator
55
54
  -------------------------------
55
+ ```sh
56
+ # use the keys from your app in the partners area
57
+ $ rails generate shopify_app --api_key <shopify_api_key> --secret <shopify_api_secret>
58
+ $ git add .
59
+ $ git commit -m 'generated shopify app'
56
60
  ```
57
- use the keys from your app in the partners area
58
- rails generate shopify_app --api_key a366cbafaccebd2f615aebdfc932fa1c --secret 8750306a895b3dbc7f4136c2ae2ea293
59
- git add .
60
- git commit -m 'generated shopify app'
61
- ```
61
+
62
+ If you forget to set your keys or redirect uri above, you will find them in the shopify_app initializer at: `/config/initializers/shopify_app.rb`.
63
+
64
+ We recommend adding a gem or utilizing ENV variables to handle your keys before releasing your app.
62
65
 
63
66
  6. Deploy
64
67
  ---------
65
- ```
66
- git push heroku
67
- heroku run rake db:migrate
68
+ ```sh
69
+ $ git push heroku
70
+ $ heroku run rake db:migrate
68
71
  ```
69
72
 
70
73
  7. Install the App!
data/docs/Releasing.md ADDED
@@ -0,0 +1,18 @@
1
+ Releasing ShopifyApp
2
+
3
+ 1. Check the Semantic Versioning page for info on how to version the new release: http://semver.org
4
+ 2. Create a pull request with the following changes:
5
+ * Update the version of ShopifyApp in lib/shopify_app/version.rb
6
+ * Update the version in package.json
7
+ * Add a CHANGELOG entry for the new release with the date
8
+ * Change the title of the PR to something like: "Packaging for release X.Y.Z"
9
+ 3. Merge your pull request
10
+ 4. Pull from master so you have the latest version of the shopify_app
11
+ 5. Tag the HEAD with the version (Leave REV blank for HEAD or provide a SHA)
12
+ $ git tag vX.Y.Z
13
+ 6. Push out your tags
14
+ $ git push --tags
15
+ 7. Use Shipit to build and push the gem
16
+
17
+ If you see an error like 'You need to create the vX.Y.X tag first', clear GIT
18
+ cache in Shipit settings
@@ -0,0 +1,16 @@
1
+ Troubleshooting Shopify App
2
+ ===========
3
+
4
+ ### Generator shopify_app:install hangs
5
+
6
+ Rails uses spring by default to speed up development. To run the generator, spring has to be stopped:
7
+
8
+ ```sh
9
+ $ bundle exec spring stop
10
+ ```
11
+
12
+ Run shopify_app generator again.
13
+
14
+ ### App installation fails with 'The page you’re looking for could not be found' if the app was installed before
15
+
16
+ This issue can occur when the session (the model you set as `ShopifyApp::SessionRepository.storage`) isn't deleted when the user uninstalls your app. A possible fix for this is listening to the `app/uninstalled` webhook and deleting the corresponding session in the webhook handler.
data/karma.conf.js ADDED
@@ -0,0 +1,43 @@
1
+ const karmaReporters = ['mocha-clean'];
2
+
3
+ function isDebug(argument) {
4
+ return argument === '--debug';
5
+ }
6
+
7
+ module.exports = function(config) {
8
+ config.set({
9
+ mode: 'development',
10
+ basePath: '',
11
+ frameworks: ['mocha-debug', 'mocha', 'chai-sinon'],
12
+ files: [
13
+ 'app/assets/javascripts/**/*.js',
14
+ 'test/javascripts/**/*test.js',
15
+ ],
16
+ exclude: [
17
+ // Exclude JS files that create 'DOMContentLoaded' event listeners
18
+ 'app/assets/javascripts/**/redirect.js',
19
+ 'app/assets/javascripts/**/storage_access_redirect.js',
20
+ 'app/assets/javascripts/**/top_level_interaction.js',
21
+ 'app/assets/javascripts/**/partition_cookies.js',
22
+ ],
23
+ mochaReporter: {
24
+ output: 'autowatch',
25
+ },
26
+ preprocessors: {
27
+ 'test/javascripts/**/*test.js': ['webpack'],
28
+ },
29
+ reporters: karmaReporters,
30
+ port: 9876,
31
+ colors: true,
32
+ logLevel: config.LOG_WARN,
33
+ autoWatch: false,
34
+ browsers: ['ChromeHeadless'],
35
+ singleRun: true,
36
+ client: {
37
+ mocha: {
38
+ ui: 'tdd',
39
+ grep: config.grep,
40
+ },
41
+ },
42
+ });
43
+ };
@@ -0,0 +1,45 @@
1
+ require 'rails/generators/base'
2
+
3
+ module ShopifyApp
4
+ module Generators
5
+ class AddAfterAuthenticateJobGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ hook_for :test_framework, as: :job, in: :rails do |instance, generator|
9
+ instance.invoke generator, [ instance.send(:job_file_name) ]
10
+ end
11
+
12
+ def init_after_authenticate_config
13
+ initializer = load_initializer
14
+
15
+ after_authenticate_job_config =
16
+ " config.after_authenticate_job = "\
17
+ "{ job: Shopify::AfterAuthenticateJob, inline: false }\n"
18
+
19
+ inject_into_file(
20
+ 'config/initializers/shopify_app.rb',
21
+ after_authenticate_job_config,
22
+ before: 'end'
23
+ )
24
+
25
+ unless initializer.include?(after_authenticate_job_config)
26
+ shell.say "Error adding after_authneticate_job to config. Add this line manually: #{after_authenticate_job_config}", :red
27
+ end
28
+ end
29
+
30
+ def add_after_authenticate_job
31
+ template 'after_authenticate_job.rb', "app/jobs/#{job_file_name}_job.rb"
32
+ end
33
+
34
+ private
35
+
36
+ def load_initializer
37
+ File.read(File.join(destination_root, 'config/initializers/shopify_app.rb'))
38
+ end
39
+
40
+ def job_file_name
41
+ 'shopify/after_authenticate'
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,10 @@
1
+ module Shopify
2
+ class AfterAuthenticateJob < ActiveJob::Base
3
+ def perform(shop_domain:)
4
+ shop = Shop.find_by(shopify_domain: shop_domain)
5
+
6
+ shop.with_shopify_session do
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,6 @@
1
1
  class HomeController < ShopifyApp::AuthenticatedController
2
2
  def index
3
3
  @products = ShopifyAPI::Product.find(:all, params: { limit: 10 })
4
+ @webhooks = ShopifyAPI::Webhook.find(:all)
4
5
  end
5
6
  end
@@ -5,3 +5,17 @@
5
5
  <li><%= link_to product.title, "https://#{@shop_session.url}/admin/products/#{product.id}", target: "_top" %></li>
6
6
  <% end %>
7
7
  </ul>
8
+
9
+ <hr>
10
+
11
+ <h2>Webhooks</h2>
12
+
13
+ <% if @webhooks.present? %>
14
+ <ul>
15
+ <% @webhooks.each do |webhook| %>
16
+ <li><%= webhook.topic %> : <%= webhook.address %></li>
17
+ <% end %>
18
+ </ul>
19
+ <% else %>
20
+ <p>This app has not created any webhooks for this Shop. Add webhooks to your ShopifyApp initializer if you need webhooks</p>
21
+ <% end %>
@@ -1,11 +1,7 @@
1
1
  <% content_for :javascript do %>
2
2
  <script type="text/javascript">
3
3
  ShopifyApp.ready(function(){
4
- ShopifyApp.Bar.initialize({
5
- title: "Home",
6
- icon: "<%= asset_path('favicon.ico') %>"
7
- });
4
+ ShopifyApp.Bar.initialize({ title: "Home" });
8
5
  });
9
6
  </script>
10
7
  <% end %>
11
-
@@ -1,5 +1,4 @@
1
1
  require 'rails/generators/base'
2
- require 'rails/generators/active_record'
3
2
 
4
3
  module ShopifyApp
5
4
  module Generators
@@ -7,17 +6,19 @@ module ShopifyApp
7
6
  include Rails::Generators::Migration
8
7
  source_root File.expand_path('../templates', __FILE__)
9
8
 
10
- class_option :application_name, type: :string
9
+ class_option :application_name, type: :array, default: ['My', 'Shopify', 'App']
11
10
  class_option :api_key, type: :string, default: '<api_key>'
12
11
  class_option :secret, type: :string, default: '<secret>'
13
- class_option :scope, type: :string, default: 'read_orders, read_products'
12
+ class_option :old_secret, type: :string, default: '<old_secret>'
13
+ class_option :scope, type: :array, default: ['read_products']
14
14
  class_option :embedded, type: :string, default: 'true'
15
15
 
16
16
  def create_shopify_app_initializer
17
- @application_name = options['application_name']
17
+ @application_name = format_array_argument(options['application_name'])
18
18
  @api_key = options['api_key']
19
19
  @secret = options['secret']
20
- @scope = options['scope']
20
+ @old_secret = options['old_secret']
21
+ @scope = format_array_argument(options['scope'])
21
22
 
22
23
  template 'shopify_app.rb', 'config/initializers/shopify_app.rb'
23
24
  end
@@ -34,17 +35,6 @@ module ShopifyApp
34
35
  )
35
36
  end
36
37
 
37
- def create_shopify_session_repository_initializer
38
- copy_file 'shopify_session_repository.rb', 'config/initializers/shopify_session_repository.rb'
39
- end
40
-
41
- def inject_embedded_app_options_to_application
42
- if embedded_app?
43
- application "config.action_dispatch.default_headers.delete('X-Frame-Options')"
44
- application "config.action_dispatch.default_headers['P3P'] = 'CP=\"Not used\"'"
45
- end
46
- end
47
-
48
38
  def create_embedded_app_layout
49
39
  if embedded_app?
50
40
  copy_file 'embedded_app.html.erb', 'app/views/layouts/embedded_app.html.erb'
@@ -61,6 +51,10 @@ module ShopifyApp
61
51
  def embedded_app?
62
52
  options['embedded'] == 'true'
63
53
  end
54
+
55
+ def format_array_argument(array)
56
+ array.join(' ').tr('"', '')
57
+ end
64
58
  end
65
59
  end
66
60
  end
@@ -1,15 +1,19 @@
1
1
  <% content_for :javascript do %>
2
2
  <script type="text/javascript">
3
- var eventName = typeof(Turbolinks) !== 'undefined' ? 'page:change' : 'DOMContentLoaded';
3
+ var eventName = typeof(Turbolinks) !== 'undefined' ? 'turbolinks:load' : 'DOMContentLoaded';
4
4
 
5
- document.addEventListener(eventName, function() {
6
- <% if flash[:notice] %>
7
- ShopifyApp.flashNotice("<%= j flash[:notice].html_safe %>");
8
- <% end %>
5
+ if (!document.documentElement.hasAttribute("data-turbolinks-preview")) {
6
+ document.addEventListener(eventName, function flash() {
7
+ <% if flash[:notice] %>
8
+ ShopifyApp.flashNotice(<%== flash[:notice].to_json %>);
9
+ <% end %>
9
10
 
10
- <% if flash[:error] %>
11
- ShopifyApp.flashError("<%= j flash[:error].html_safe %>");
12
- <% end %>
13
- });
11
+ <% if flash[:error] %>
12
+ ShopifyApp.flashError(<%== flash[:error].to_json %>);
13
+ <% end %>
14
+
15
+ document.removeEventListener(eventName, flash)
16
+ });
17
+ }
14
18
  </script>
15
19
  <% end %>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <% application_name = ShopifyApp.configuration.application_name %>
6
- <title><%= application_name.presence || 'Embedded Shopify App Example' %></title>
6
+ <title><%= application_name %></title>
7
7
  <%= stylesheet_link_tag 'application' %>
8
8
  <%= javascript_include_tag 'application', "data-turbolinks-track" => true %>
9
9
  <%= csrf_meta_tags %>
@@ -1,9 +1,11 @@
1
1
  ShopifyApp.configure do |config|
2
- <% if @application_name.present? %>
3
2
  config.application_name = "<%= @application_name %>"
4
- <% end %>
5
3
  config.api_key = "<%= @api_key %>"
6
4
  config.secret = "<%= @secret %>"
7
- config.scope = "<%= @scope %>"
5
+ config.old_secret = "<%= @old_secret %>"
6
+ config.scope = "<%= @scope %>" # Consult this page for more scope options:
7
+ # https://help.shopify.com/en/api/getting-started/authentication/oauth/scopes
8
8
  config.embedded_app = <%= embedded_app? %>
9
+ config.after_authenticate_job = false
10
+ config.session_repository = ShopifyApp::InMemorySessionStore
9
11
  end
@@ -1,4 +1,19 @@
1
- provider :shopify,
2
- ShopifyApp.configuration.api_key,
3
- ShopifyApp.configuration.secret,
4
- scope: ShopifyApp.configuration.scope
1
+ # frozen_string_literal: true
2
+
3
+ provider :shopify,
4
+ ShopifyApp.configuration.api_key,
5
+ ShopifyApp.configuration.secret,
6
+ scope: ShopifyApp.configuration.scope,
7
+ setup: lambda { |env|
8
+ strategy = env['omniauth.strategy']
9
+
10
+ shopify_auth_params = strategy.session['shopify.omniauth_params']&.with_indifferent_access
11
+ shop = if shopify_auth_params.present?
12
+ "https://#{shopify_auth_params[:shop]}"
13
+ else
14
+ ''
15
+ end
16
+
17
+ strategy.options[:client_options][:site] = shop
18
+ strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
19
+ }
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/base'
4
+
5
+ module ShopifyApp
6
+ module Generators
7
+ class RotateShopifyTokenJobGenerator < Rails::Generators::Base
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ def add_rotate_shopify_token_job
11
+ copy_file('rotate_shopify_token_job.rb', "app/jobs/shopify/rotate_shopify_token_job.rb")
12
+ copy_file('rotate_shopify_token.rake', "lib/tasks/shopify/rotate_shopify_token.rake")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ namespace :shopify do
3
+ desc "Rotate shopify tokens for all active shops"
4
+ task :rotate_shopify_tokens, [:refresh_token] => :environment do |_t, args|
5
+ all_active_shops.find_each do |shop|
6
+ Shopify::RotateShopifyTokenJob.perform_later(
7
+ shop_domain: shop.shopify_domain,
8
+ refresh_token: args[:refresh_token]
9
+ )
10
+ end
11
+ end
12
+
13
+ # Its implementation will depend on the app configuration. Change accordingly.
14
+ def all_active_shops
15
+ Shop.all
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shopify
4
+ class RotateShopifyTokenJob < ActiveJob::Base
5
+ def perform(params)
6
+ @shop = Shop.find_by(shopify_domain: params[:shop_domain])
7
+ return unless @shop
8
+
9
+ config = ShopifyApp.configuration
10
+ uri = URI("https://#{@shop.shopify_domain}/admin/oauth/access_token")
11
+ post_data = {
12
+ client_id: config.api_key,
13
+ client_secret: config.secret,
14
+ refresh_token: params[:refresh_token],
15
+ access_token: @shop.shopify_token,
16
+ }
17
+
18
+ @response = Net::HTTP.post_form(uri, post_data)
19
+ return log_error(response_expcetion_error_message) unless @response.is_a?(Net::HTTPSuccess)
20
+
21
+ access_token = JSON.parse(@response.body)['access_token']
22
+ return log_error(no_access_token_error_message) unless access_token
23
+
24
+ @shop.update(shopify_token: access_token)
25
+ end
26
+
27
+ private
28
+
29
+ def log_error(message)
30
+ Rails.logger.error(message)
31
+ end
32
+
33
+ def no_access_token_error_message
34
+ "RotateShopifyTokenJob response returned no access token for shop: #{@shop.shopify_domain}"
35
+ end
36
+
37
+ def response_exception_error_message
38
+ "RotateShopifyTokenJob failed for shop: #{@shop.shopify_domain}." \
39
+ "Response returned status: #{@response.code}. Error message: #{@response.message}. "
40
+ end
41
+ end
42
+ end