shopify_app 12.0.0 → 17.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE/bug-report.md +63 -0
- data/.github/ISSUE_TEMPLATE/config.yml +1 -0
- data/.github/ISSUE_TEMPLATE/feature-request.md +33 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- data/.github/workflows/build.yml +41 -0
- data/.github/workflows/release.yml +24 -0
- data/.github/workflows/rubocop.yml +22 -0
- data/.gitignore +0 -2
- data/.rubocop.yml +14 -6
- data/CHANGELOG.md +180 -0
- data/CONTRIBUTING.md +76 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +257 -0
- data/README.md +72 -487
- data/Rakefile +1 -0
- data/SECURITY.md +59 -0
- data/app/assets/images/storage_access.svg +1 -2
- data/app/assets/javascripts/shopify_app/itp_helper.js +6 -6
- data/app/assets/javascripts/shopify_app/storage_access.js +37 -7
- data/app/assets/javascripts/shopify_app/top_level_interaction.js +1 -1
- data/app/controllers/concerns/shopify_app/authenticated.rb +2 -1
- data/app/controllers/concerns/shopify_app/ensure_authenticated_links.rb +26 -0
- data/app/controllers/concerns/shopify_app/require_known_shop.rb +39 -0
- data/app/controllers/concerns/shopify_app/shop_access_scopes_verification.rb +32 -0
- data/app/controllers/shopify_app/authenticated_controller.rb +1 -0
- data/app/controllers/shopify_app/callback_controller.rb +113 -23
- data/app/controllers/shopify_app/extension_verification_controller.rb +2 -7
- data/app/controllers/shopify_app/sessions_controller.rb +62 -14
- data/app/controllers/shopify_app/webhooks_controller.rb +6 -5
- data/app/views/shopify_app/partials/_button_styles.html.erb +41 -36
- data/app/views/shopify_app/partials/_card_styles.html.erb +3 -3
- data/app/views/shopify_app/partials/_empty_state_styles.html.erb +28 -59
- data/app/views/shopify_app/partials/_form_styles.html.erb +56 -0
- data/app/views/shopify_app/partials/_layout_styles.html.erb +16 -1
- data/app/views/shopify_app/partials/_typography_styles.html.erb +6 -6
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +3 -8
- data/app/views/shopify_app/sessions/new.html.erb +38 -110
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +2 -2
- data/app/views/shopify_app/sessions/top_level_interaction.html.erb +21 -22
- data/config/locales/de.yml +11 -11
- data/config/locales/fi.yml +1 -1
- data/config/locales/nl.yml +8 -8
- data/config/locales/pt-BR.yml +1 -1
- data/config/locales/th.yml +4 -4
- data/config/locales/vi.yml +22 -0
- data/config/locales/zh-CN.yml +1 -1
- data/config/routes.rb +1 -0
- data/docs/Quickstart.md +15 -87
- data/docs/Releasing.md +18 -14
- data/docs/Troubleshooting.md +129 -4
- data/docs/Upgrading.md +126 -0
- data/docs/shopify_app/authentication.md +124 -0
- data/docs/shopify_app/engine.md +82 -0
- data/docs/shopify_app/generators.md +127 -0
- data/docs/shopify_app/handling-access-scopes-changes.md +14 -0
- data/docs/shopify_app/script-tags.md +28 -0
- data/docs/shopify_app/session-repository.md +88 -0
- data/docs/shopify_app/testing.md +38 -0
- data/docs/shopify_app/webhooks.md +72 -0
- data/karma.conf.js +1 -1
- data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +5 -3
- data/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb +1 -0
- data/lib/generators/shopify_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +2 -1
- data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +4 -8
- data/lib/generators/shopify_app/add_webhook/add_webhook_generator.rb +5 -4
- data/lib/generators/shopify_app/add_webhook/templates/{webhook_job.rb → webhook_job.rb.tt} +5 -0
- data/lib/generators/shopify_app/app_proxy_controller/app_proxy_controller_generator.rb +4 -3
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_controller.rb +3 -3
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_route.rb +10 -9
- data/lib/generators/shopify_app/authenticated_controller/authenticated_controller_generator.rb +1 -1
- data/lib/generators/shopify_app/controllers/controllers_generator.rb +2 -1
- data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +31 -3
- data/lib/generators/shopify_app/home_controller/templates/home_controller.rb +2 -0
- data/lib/generators/shopify_app/home_controller/templates/index.html.erb +66 -16
- data/lib/generators/shopify_app/home_controller/templates/unauthenticated_home_controller.rb +11 -0
- data/lib/generators/shopify_app/install/install_generator.rb +46 -11
- data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +1 -1
- data/lib/generators/shopify_app/install/templates/flash_messages.js +0 -2
- data/lib/generators/shopify_app/install/templates/omniauth.rb +3 -1
- data/lib/generators/shopify_app/install/templates/shopify_app.rb.tt +25 -0
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb.tt +8 -0
- data/lib/generators/shopify_app/install/templates/user_agent.rb +2 -1
- data/lib/generators/shopify_app/products_controller/products_controller_generator.rb +19 -0
- data/lib/generators/shopify_app/products_controller/templates/products_controller.rb +8 -0
- data/lib/generators/shopify_app/routes/routes_generator.rb +1 -0
- data/lib/generators/shopify_app/routes/templates/routes.rb +10 -9
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +39 -7
- data/lib/generators/shopify_app/shop_model/templates/db/migrate/add_shop_access_scopes_column.erb +5 -0
- data/lib/generators/shopify_app/shop_model/templates/shop.rb +2 -1
- data/lib/generators/shopify_app/shopify_app_generator.rb +4 -3
- data/lib/generators/shopify_app/user_model/templates/db/migrate/add_user_access_scopes_column.erb +5 -0
- data/lib/generators/shopify_app/user_model/templates/user.rb +2 -1
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +39 -7
- data/lib/generators/shopify_app/views/views_generator.rb +2 -1
- data/lib/shopify_app/access_scopes/noop_strategy.rb +13 -0
- data/lib/shopify_app/access_scopes/shop_strategy.rb +24 -0
- data/lib/shopify_app/access_scopes/user_strategy.rb +41 -0
- data/lib/shopify_app/configuration.rb +46 -11
- data/lib/shopify_app/controller_concerns/app_proxy_verification.rb +3 -3
- data/lib/shopify_app/controller_concerns/csrf_protection.rb +15 -0
- data/lib/shopify_app/controller_concerns/embedded_app.rb +3 -2
- data/lib/shopify_app/controller_concerns/localization.rb +1 -0
- data/lib/shopify_app/controller_concerns/login_protection.rb +105 -30
- data/lib/shopify_app/controller_concerns/payload_verification.rb +24 -0
- data/lib/shopify_app/controller_concerns/webhook_verification.rb +3 -18
- data/lib/shopify_app/engine.rb +27 -1
- data/lib/shopify_app/jobs/scripttags_manager_job.rb +1 -1
- data/lib/shopify_app/jobs/webhooks_manager_job.rb +1 -1
- data/lib/shopify_app/managers/scripttags_manager.rb +4 -3
- data/lib/shopify_app/managers/webhooks_manager.rb +4 -3
- data/lib/shopify_app/middleware/jwt_middleware.rb +42 -0
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +19 -45
- data/lib/shopify_app/omniauth/omniauth_configuration.rb +64 -0
- data/lib/shopify_app/session/in_memory_session_store.rb +7 -3
- data/lib/shopify_app/session/in_memory_shop_session_store.rb +16 -0
- data/lib/shopify_app/session/in_memory_user_session_store.rb +16 -0
- data/lib/shopify_app/session/jwt.rb +63 -0
- data/lib/shopify_app/session/null_user_session_store.rb +22 -0
- data/lib/shopify_app/session/session_repository.rb +36 -14
- data/lib/shopify_app/session/session_storage.rb +1 -10
- data/lib/shopify_app/session/shop_session_storage.rb +42 -0
- data/lib/shopify_app/session/shop_session_storage_with_scopes.rb +58 -0
- data/lib/shopify_app/session/user_session_storage.rb +42 -0
- data/lib/shopify_app/session/user_session_storage_with_scopes.rb +58 -0
- data/lib/shopify_app/test_helpers/all.rb +2 -0
- data/lib/shopify_app/test_helpers/webhook_verification_helper.rb +17 -0
- data/lib/shopify_app/utils.rb +18 -5
- data/lib/shopify_app/version.rb +2 -1
- data/lib/shopify_app.rb +24 -5
- data/package.json +8 -9
- data/shopify_app.gemspec +15 -10
- data/translation.yml +1 -1
- data/yarn.lock +2120 -2168
- metadata +94 -20
- data/.github/ISSUE_TEMPLATE.md +0 -14
- data/.travis.yml +0 -27
- data/docs/install-on-dev-shop.png +0 -0
- data/docs/test-your-app.png +0 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.rb +0 -15
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +0 -20
- data/lib/shopify_app/session/storage_strategies/shop_storage_strategy.rb +0 -23
- data/lib/shopify_app/session/storage_strategies/user_storage_strategy.rb +0 -24
- data/package-lock.json +0 -7224
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Contributing to the Shopify App gem
|
2
|
+
|
3
|
+
The following is a set of guidelines for contributing to the Shopify App gem. These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request.
|
4
|
+
|
5
|
+
#### Table of contents
|
6
|
+
|
7
|
+
[I just have a question!](#i-just-have-a-question)
|
8
|
+
|
9
|
+
[How can I contribute?](#how-can-i-contribute)
|
10
|
+
* [Reporting bugs](#reporting-bugs)
|
11
|
+
* [Suggesting or requesting improvements](#suggesting-or-requesting-improvements)
|
12
|
+
* [Pull requests](#pull-requests)
|
13
|
+
|
14
|
+
## I just have a question!
|
15
|
+
|
16
|
+
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
|
17
|
+
|
18
|
+
Shopify has an official message board with dedicated forums to discuss all things apps, APIs, SDKs and more.
|
19
|
+
|
20
|
+
#### Shopify Community forum links
|
21
|
+
|
22
|
+
* [Shopify Community](https://community.shopify.com)
|
23
|
+
* [Shopify Apps](https://community.shopify.com/c/Shopify-Apps/bd-p/shopify-apps)
|
24
|
+
* [Shopify APIs & SDKs](https://community.shopify.com/c/Shopify-APIs-SDKs/bd-p/shopify-apis-and-technology)
|
25
|
+
|
26
|
+
If you prefer to chat instead, join the [Shopify Partners Slack Community group](https://www.shopify.com/partners/community#conversation). This Slack group hosts an active community of thousands of app developers.
|
27
|
+
|
28
|
+
By participating in the Community forum or Slack group, you agree to adhere to the forum [Code of Conduct](https://community.shopify.com/c/Announcements/Code-of-Conduct/m-p/491969#M23) outlined.
|
29
|
+
|
30
|
+
## How can I contribute?
|
31
|
+
|
32
|
+
### Reporting bugs
|
33
|
+
|
34
|
+
This section guides you through submitting a bug report for the Shopify App gem. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
|
35
|
+
|
36
|
+
#### Before submitting a bug report
|
37
|
+
|
38
|
+
* **Check the [troubleshooting guide](/docs/Troubleshooting.md).** You may be able to troubleshoot the issue you're facing.
|
39
|
+
* **Check the [Shopify Community links](#shopify-community-forum-links) to search for your issue.** This problem may have been reported before and solved on the Shopify forum.
|
40
|
+
* **Perform a cursory search for similar issues.** You may find that the same problem (or a similar one) has been filed already as an issue.
|
41
|
+
|
42
|
+
#### How do I submit a good bug report?
|
43
|
+
|
44
|
+
Bugs are tracked as GitHub issues. Create an issue and provide the following information by filling in the [bug-report template](/.github/ISSUE_TEMPLATE/bug-report.md).
|
45
|
+
|
46
|
+
Explain the problem and include additional details to help maintainers reproduce the problem:
|
47
|
+
|
48
|
+
* **Use a clear and descriptive title** for the issue to identify the problem.
|
49
|
+
* **Describe the exact steps which reproduce the problem** in as many details as possible.
|
50
|
+
* **Provide specific examples to demonstrate the steps.** Include links to files, or copy/pasteable snippets. If you're providing snippets in the issue, use Markdown code blocks.
|
51
|
+
* **Describe the behavior you observed** after following the steps and point out what exactly is the problem with that behavior.
|
52
|
+
* **Explain which behavior you expected to see** instead and why.
|
53
|
+
* **Include screenshots and animated GIFs** where possible.
|
54
|
+
* **Redact any private information** from your logs and issue description. This includes things like API keys, API secrets, and any access tokens.
|
55
|
+
|
56
|
+
### Suggesting or requesting improvements
|
57
|
+
|
58
|
+
If you have a suggestion for the Shopify App gem or a feature request, provide the appropriate information by filling out the [feature-request template](/.github/ISSUE_TEMPLATE/feature-request.md).
|
59
|
+
|
60
|
+
### Pull requests
|
61
|
+
|
62
|
+
The process described here has several goals:
|
63
|
+
|
64
|
+
* Maintain the Shopify App gem's quality
|
65
|
+
* Fix problems that are important to app developers
|
66
|
+
* Enable a sustainable system for the Shopify App gem's maintainers to review contributions
|
67
|
+
|
68
|
+
Please follow these steps to have your contribution considered by the maintainers:
|
69
|
+
|
70
|
+
* Follow all instructions in the [pull request template](/.github/PULL_REQUEST_TEMPLATE.md)
|
71
|
+
* After you submit your pull request, verify that all status checks are passing
|
72
|
+
* <details>
|
73
|
+
<summary>What if the status checks are failing?</summary>
|
74
|
+
|
75
|
+
While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.
|
76
|
+
</details>
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
shopify_app (17.2.0)
|
5
|
+
browser_sniffer (~> 1.2.2)
|
6
|
+
jwt (~> 2.2.1)
|
7
|
+
omniauth-shopify-oauth2 (~> 2.2.2)
|
8
|
+
rails (> 5.2.1, < 6.2)
|
9
|
+
redirect_safely (~> 1.0)
|
10
|
+
shopify_api (~> 9.4)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
actioncable (6.1.3.1)
|
16
|
+
actionpack (= 6.1.3.1)
|
17
|
+
activesupport (= 6.1.3.1)
|
18
|
+
nio4r (~> 2.0)
|
19
|
+
websocket-driver (>= 0.6.1)
|
20
|
+
actionmailbox (6.1.3.1)
|
21
|
+
actionpack (= 6.1.3.1)
|
22
|
+
activejob (= 6.1.3.1)
|
23
|
+
activerecord (= 6.1.3.1)
|
24
|
+
activestorage (= 6.1.3.1)
|
25
|
+
activesupport (= 6.1.3.1)
|
26
|
+
mail (>= 2.7.1)
|
27
|
+
actionmailer (6.1.3.1)
|
28
|
+
actionpack (= 6.1.3.1)
|
29
|
+
actionview (= 6.1.3.1)
|
30
|
+
activejob (= 6.1.3.1)
|
31
|
+
activesupport (= 6.1.3.1)
|
32
|
+
mail (~> 2.5, >= 2.5.4)
|
33
|
+
rails-dom-testing (~> 2.0)
|
34
|
+
actionpack (6.1.3.1)
|
35
|
+
actionview (= 6.1.3.1)
|
36
|
+
activesupport (= 6.1.3.1)
|
37
|
+
rack (~> 2.0, >= 2.0.9)
|
38
|
+
rack-test (>= 0.6.3)
|
39
|
+
rails-dom-testing (~> 2.0)
|
40
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
41
|
+
actiontext (6.1.3.1)
|
42
|
+
actionpack (= 6.1.3.1)
|
43
|
+
activerecord (= 6.1.3.1)
|
44
|
+
activestorage (= 6.1.3.1)
|
45
|
+
activesupport (= 6.1.3.1)
|
46
|
+
nokogiri (>= 1.8.5)
|
47
|
+
actionview (6.1.3.1)
|
48
|
+
activesupport (= 6.1.3.1)
|
49
|
+
builder (~> 3.1)
|
50
|
+
erubi (~> 1.4)
|
51
|
+
rails-dom-testing (~> 2.0)
|
52
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
53
|
+
activejob (6.1.3.1)
|
54
|
+
activesupport (= 6.1.3.1)
|
55
|
+
globalid (>= 0.3.6)
|
56
|
+
activemodel (6.1.3.1)
|
57
|
+
activesupport (= 6.1.3.1)
|
58
|
+
activemodel-serializers-xml (1.0.2)
|
59
|
+
activemodel (> 5.x)
|
60
|
+
activesupport (> 5.x)
|
61
|
+
builder (~> 3.1)
|
62
|
+
activerecord (6.1.3.1)
|
63
|
+
activemodel (= 6.1.3.1)
|
64
|
+
activesupport (= 6.1.3.1)
|
65
|
+
activeresource (5.1.1)
|
66
|
+
activemodel (>= 5.0, < 7)
|
67
|
+
activemodel-serializers-xml (~> 1.0)
|
68
|
+
activesupport (>= 5.0, < 7)
|
69
|
+
activestorage (6.1.3.1)
|
70
|
+
actionpack (= 6.1.3.1)
|
71
|
+
activejob (= 6.1.3.1)
|
72
|
+
activerecord (= 6.1.3.1)
|
73
|
+
activesupport (= 6.1.3.1)
|
74
|
+
marcel (~> 1.0.0)
|
75
|
+
mini_mime (~> 1.0.2)
|
76
|
+
activesupport (6.1.3.1)
|
77
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
78
|
+
i18n (>= 1.6, < 2)
|
79
|
+
minitest (>= 5.1)
|
80
|
+
tzinfo (~> 2.0)
|
81
|
+
zeitwerk (~> 2.3)
|
82
|
+
addressable (2.7.0)
|
83
|
+
public_suffix (>= 2.0.2, < 5.0)
|
84
|
+
ast (2.4.1)
|
85
|
+
binding_of_caller (0.8.0)
|
86
|
+
debug_inspector (>= 0.0.1)
|
87
|
+
browser_sniffer (1.2.2)
|
88
|
+
builder (3.2.4)
|
89
|
+
byebug (11.1.3)
|
90
|
+
coderay (1.1.3)
|
91
|
+
concurrent-ruby (1.1.8)
|
92
|
+
crack (0.4.4)
|
93
|
+
crass (1.0.6)
|
94
|
+
debug_inspector (0.0.3)
|
95
|
+
erubi (1.10.0)
|
96
|
+
faraday (1.3.0)
|
97
|
+
faraday-net_http (~> 1.0)
|
98
|
+
multipart-post (>= 1.2, < 3)
|
99
|
+
ruby2_keywords
|
100
|
+
faraday-net_http (1.0.1)
|
101
|
+
globalid (0.4.2)
|
102
|
+
activesupport (>= 4.2.0)
|
103
|
+
graphql (1.12.6)
|
104
|
+
graphql-client (0.16.0)
|
105
|
+
activesupport (>= 3.0)
|
106
|
+
graphql (~> 1.8)
|
107
|
+
hashdiff (1.0.1)
|
108
|
+
hashie (4.1.0)
|
109
|
+
i18n (1.8.9)
|
110
|
+
concurrent-ruby (~> 1.0)
|
111
|
+
jwt (2.2.2)
|
112
|
+
loofah (2.9.0)
|
113
|
+
crass (~> 1.0.2)
|
114
|
+
nokogiri (>= 1.5.9)
|
115
|
+
mail (2.7.1)
|
116
|
+
mini_mime (>= 0.1.1)
|
117
|
+
marcel (1.0.0)
|
118
|
+
method_source (0.9.2)
|
119
|
+
mini_mime (1.0.3)
|
120
|
+
mini_portile2 (2.5.0)
|
121
|
+
minitest (5.14.4)
|
122
|
+
mocha (1.11.2)
|
123
|
+
multi_json (1.15.0)
|
124
|
+
multi_xml (0.6.0)
|
125
|
+
multipart-post (2.1.1)
|
126
|
+
nio4r (2.5.7)
|
127
|
+
nokogiri (1.11.2)
|
128
|
+
mini_portile2 (~> 2.5.0)
|
129
|
+
racc (~> 1.4)
|
130
|
+
oauth2 (1.4.7)
|
131
|
+
faraday (>= 0.8, < 2.0)
|
132
|
+
jwt (>= 1.0, < 3.0)
|
133
|
+
multi_json (~> 1.3)
|
134
|
+
multi_xml (~> 0.5)
|
135
|
+
rack (>= 1.2, < 3)
|
136
|
+
omniauth (1.9.1)
|
137
|
+
hashie (>= 3.4.6)
|
138
|
+
rack (>= 1.6.2, < 3)
|
139
|
+
omniauth-oauth2 (1.5.0)
|
140
|
+
oauth2 (~> 1.1)
|
141
|
+
omniauth (~> 1.2)
|
142
|
+
omniauth-shopify-oauth2 (2.2.3)
|
143
|
+
activesupport
|
144
|
+
omniauth-oauth2 (~> 1.5.0)
|
145
|
+
parallel (1.20.1)
|
146
|
+
parser (2.7.2.0)
|
147
|
+
ast (~> 2.4.1)
|
148
|
+
pry (0.12.2)
|
149
|
+
coderay (~> 1.1.0)
|
150
|
+
method_source (~> 0.9.0)
|
151
|
+
pry-nav (0.3.0)
|
152
|
+
pry (>= 0.9.10, < 0.13.0)
|
153
|
+
pry-stack_explorer (0.4.9.3)
|
154
|
+
binding_of_caller (>= 0.7)
|
155
|
+
pry (>= 0.9.11)
|
156
|
+
public_suffix (4.0.6)
|
157
|
+
racc (1.5.2)
|
158
|
+
rack (2.2.3)
|
159
|
+
rack-test (1.1.0)
|
160
|
+
rack (>= 1.0, < 3)
|
161
|
+
rails (6.1.3.1)
|
162
|
+
actioncable (= 6.1.3.1)
|
163
|
+
actionmailbox (= 6.1.3.1)
|
164
|
+
actionmailer (= 6.1.3.1)
|
165
|
+
actionpack (= 6.1.3.1)
|
166
|
+
actiontext (= 6.1.3.1)
|
167
|
+
actionview (= 6.1.3.1)
|
168
|
+
activejob (= 6.1.3.1)
|
169
|
+
activemodel (= 6.1.3.1)
|
170
|
+
activerecord (= 6.1.3.1)
|
171
|
+
activestorage (= 6.1.3.1)
|
172
|
+
activesupport (= 6.1.3.1)
|
173
|
+
bundler (>= 1.15.0)
|
174
|
+
railties (= 6.1.3.1)
|
175
|
+
sprockets-rails (>= 2.0.0)
|
176
|
+
rails-controller-testing (1.0.5)
|
177
|
+
actionpack (>= 5.0.1.rc1)
|
178
|
+
actionview (>= 5.0.1.rc1)
|
179
|
+
activesupport (>= 5.0.1.rc1)
|
180
|
+
rails-dom-testing (2.0.3)
|
181
|
+
activesupport (>= 4.2.0)
|
182
|
+
nokogiri (>= 1.6)
|
183
|
+
rails-html-sanitizer (1.3.0)
|
184
|
+
loofah (~> 2.3)
|
185
|
+
railties (6.1.3.1)
|
186
|
+
actionpack (= 6.1.3.1)
|
187
|
+
activesupport (= 6.1.3.1)
|
188
|
+
method_source
|
189
|
+
rake (>= 0.8.7)
|
190
|
+
thor (~> 1.0)
|
191
|
+
rainbow (3.0.0)
|
192
|
+
rake (13.0.3)
|
193
|
+
rb-readline (0.5.5)
|
194
|
+
redirect_safely (1.0.0)
|
195
|
+
activemodel
|
196
|
+
regexp_parser (2.0.0)
|
197
|
+
rexml (3.2.4)
|
198
|
+
rubocop (1.5.2)
|
199
|
+
parallel (~> 1.10)
|
200
|
+
parser (>= 2.7.1.5)
|
201
|
+
rainbow (>= 2.2.2, < 4.0)
|
202
|
+
regexp_parser (>= 1.8, < 3.0)
|
203
|
+
rexml
|
204
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
205
|
+
ruby-progressbar (~> 1.7)
|
206
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
207
|
+
rubocop-ast (1.3.0)
|
208
|
+
parser (>= 2.7.1.5)
|
209
|
+
rubocop-shopify (1.0.7)
|
210
|
+
rubocop (~> 1.4)
|
211
|
+
ruby-progressbar (1.10.1)
|
212
|
+
ruby2_keywords (0.0.4)
|
213
|
+
shopify_api (9.4.1)
|
214
|
+
activeresource (>= 4.1.0, < 6.0.0)
|
215
|
+
graphql-client
|
216
|
+
rack
|
217
|
+
sprockets (4.0.2)
|
218
|
+
concurrent-ruby (~> 1.0)
|
219
|
+
rack (> 1, < 3)
|
220
|
+
sprockets-rails (3.2.2)
|
221
|
+
actionpack (>= 4.0)
|
222
|
+
activesupport (>= 4.0)
|
223
|
+
sprockets (>= 3.0.0)
|
224
|
+
sqlite3 (1.4.2)
|
225
|
+
thor (1.1.0)
|
226
|
+
tzinfo (2.0.4)
|
227
|
+
concurrent-ruby (~> 1.0)
|
228
|
+
unicode-display_width (1.7.0)
|
229
|
+
webmock (3.9.1)
|
230
|
+
addressable (>= 2.3.6)
|
231
|
+
crack (>= 0.3.2)
|
232
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
233
|
+
websocket-driver (0.7.3)
|
234
|
+
websocket-extensions (>= 0.1.0)
|
235
|
+
websocket-extensions (0.1.5)
|
236
|
+
zeitwerk (2.4.2)
|
237
|
+
|
238
|
+
PLATFORMS
|
239
|
+
ruby
|
240
|
+
|
241
|
+
DEPENDENCIES
|
242
|
+
byebug
|
243
|
+
minitest
|
244
|
+
mocha
|
245
|
+
pry
|
246
|
+
pry-nav
|
247
|
+
pry-stack_explorer
|
248
|
+
rails-controller-testing
|
249
|
+
rake
|
250
|
+
rb-readline
|
251
|
+
rubocop-shopify
|
252
|
+
shopify_app!
|
253
|
+
sqlite3 (~> 1.4)
|
254
|
+
webmock
|
255
|
+
|
256
|
+
BUNDLED WITH
|
257
|
+
2.1.4
|
data/README.md
CHANGED
@@ -1,545 +1,130 @@
|
|
1
|
-
Shopify App
|
2
|
-
|
3
|
-
[![Version][gem]][gem_url] [![Build Status](https://
|
1
|
+
# Shopify App
|
2
|
+
|
3
|
+
[![Version][gem]][gem_url] [![Build Status](https://github.com/Shopify/shopify_app/workflows/CI/badge.svg)](https://github.com/Shopify/shopify_app/actions?query=workflow%3ACI) ![Supported Rails version][supported_rails_version]
|
4
4
|
|
5
5
|
[gem]: https://img.shields.io/gem/v/shopify_app.svg
|
6
6
|
[gem_url]: https://rubygems.org/gems/shopify_app
|
7
|
+
[supported_rails_version]: https://img.shields.io/badge/rails-%3C6.2.0-orange
|
7
8
|
|
9
|
+
This gem builds Rails applications that can be embedded in the Shopify Admin.
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
[Introduction](#introduction) |
|
12
|
+
[Requirements](#requirements) |
|
13
|
+
[Usage](#usage) |
|
14
|
+
[Documentation](#documentation) |
|
15
|
+
[Contributing](/CONTRIBUTING.md) |
|
16
|
+
[License](/LICENSE)
|
12
17
|
|
13
|
-
|
14
|
-
-----------------
|
15
|
-
- [Introduction](#introduction)
|
16
|
-
- [Become a Shopify App Developer](#become-a-shopify-app-developer)
|
17
|
-
- [Installation](#installation)
|
18
|
-
- [Generators](#generators)
|
19
|
-
- [Mounting the Engine](#mounting-the-engine)
|
20
|
-
- [Authentication](#authentication)
|
21
|
-
- [WebhooksManager](#webhooksmanager)
|
22
|
-
- [ScripttagsManager](#scripttagsmanager)
|
23
|
-
- [RotateShopifyTokenJob](#rotateshopifytokenjob)
|
24
|
-
- [App Tunneling](#app-tunneling)
|
25
|
-
- [AppProxyVerification](#appproxyverification)
|
26
|
-
- [Troubleshooting](#troubleshooting)
|
27
|
-
- [Testing an embedded app outside the Shopify admin](#testing-an-embedded-app-outside-the-shopify-admin)
|
28
|
-
- [Questions or problems?](#questions-or-problems-)
|
29
|
-
- [Rails 6 Compatibility](#rails-6-compatibility)
|
30
|
-
- [Upgrading from 8.6 to 9.0.0](#upgrading-from-86-to-900)
|
18
|
+
## Introduction
|
31
19
|
|
32
|
-
|
33
|
-
-----------
|
34
|
-
Get started with the [Shopify Admin API](https://help.shopify.com/en/api/getting-started) faster; This gem includes a Rails Engine and generators for writing Rails applications using the Shopify API. The Engine provides a SessionsController and all the required code for authenticating with a shop via Oauth (other authentication methods are not supported).
|
20
|
+
This gem includes a Rails engine, generators, modules, and mixins that help create Rails applications that work with Shopify APIs. The [Shopify App Rails engine](/docs/shopify_app/engine.md) provides all the code required to implement OAuth with Shopify. The [default Shopify App generator](/docs/shopify_app/generators.md#-environment-rails-generate-shopify_app) builds an app that can be embedded in the Shopify Admin and secures it with [session tokens](https://shopify.dev/concepts/apps/building-embedded-apps-using-session-tokens).
|
35
21
|
|
36
|
-
|
22
|
+
<!-- This section is linked to in `templates/shopify_app.rb.tt`. Be careful renaming this heading. -->
|
23
|
+
## Requirements
|
37
24
|
|
38
|
-
|
25
|
+
> **Rails compatibility**
|
26
|
+
> * Rails 6.1 or above is not yet supported due to the new `cookies_same_site_protection` setting.
|
27
|
+
> * Use Shopify App `<= v7.2.8` if you need to work with Rails 4.
|
39
28
|
|
40
|
-
[https://www.
|
29
|
+
To become a Shopify app developer, you will need a [Shopify Partners](https://www.shopify.com/partners) account. Explore the [Shopify dev docs](https://shopify.dev/concepts/shopify-introduction) to learn more about [building Shopify apps](https://shopify.dev/concepts/apps).
|
41
30
|
|
42
|
-
|
43
|
-
--------------------------------
|
44
|
-
To become a Shopify App Developer you'll need a [Shopify Partner account.](http://shopify.com/partners) If you don't have a Shopify Partner account, head to http://shopify.com/partners to create one before you start.
|
31
|
+
This gem requires that you have the following credentials:
|
45
32
|
|
46
|
-
|
33
|
+
- **Shopify API key:** The API key app credential specified in your [Shopify Partners dashboard](https://partners.shopify.com/organizations).
|
34
|
+
- **Shopify API secret:** The API secret key app credential specified in your [Shopify Partners dashboard](https://partners.shopify.com/organizations).
|
47
35
|
|
48
|
-
|
36
|
+
## Usage
|
49
37
|
|
50
|
-
|
51
|
-
------------
|
52
|
-
To get started add `shopify_app` to your Gemfile and run `bundle install`:
|
38
|
+
1. To get started, create a new Rails app:
|
53
39
|
|
54
40
|
``` sh
|
55
|
-
# Create a new rails app
|
56
41
|
$ rails new my_shopify_app
|
57
|
-
$ cd my_shopify_app
|
58
|
-
|
59
|
-
# Add the gem shopify_app to your Gemfile
|
60
|
-
$ echo "gem 'shopify_app'" >> Gemfile
|
61
|
-
$ bundle install
|
62
|
-
```
|
63
|
-
|
64
|
-
Now we are ready to run any of the [generators](#generators) included with `shopify_app`. The following section explains the generators and what you can do with them.
|
65
|
-
|
66
|
-
|
67
|
-
#### Rails Compatibility
|
68
|
-
|
69
|
-
The lastest version of shopify_app is compatible with Rails `>= 5`. Use version `<= v7.2.8` if you need to work with Rails 4.
|
70
|
-
|
71
|
-
|
72
|
-
Generators
|
73
|
-
----------
|
74
|
-
|
75
|
-
### Default Generator
|
76
|
-
|
77
|
-
The default generator will run the `install`, `shop`, and `home_controller` generators. This is the recommended way to start a new app from scratch:
|
78
|
-
|
79
|
-
```sh
|
80
|
-
$ rails generate shopify_app
|
81
|
-
```
|
82
|
-
|
83
|
-
After running the generator, you will need to run `rails db:migrate` to add new tables to your database. You can start your app with `bundle exec rails server` and install your app by visiting `http://localhost` in your web browser.
|
84
|
-
|
85
|
-
### API Keys
|
86
|
-
|
87
|
-
The default and install generators have been updated to source Shopify API key and secret from an Environment (`.env`) variables file, which you will need to create with the following format:
|
88
|
-
|
89
|
-
```
|
90
|
-
SHOPIFY_API_KEY=your api key
|
91
|
-
SHOPIFY_API_SECRET=your api secret
|
92
42
|
```
|
93
43
|
|
94
|
-
|
95
|
-
|
96
|
-
### Install Generator
|
44
|
+
2. Add the Shopify App gem to `my_shopify_app`'s Gemfile.
|
97
45
|
|
98
46
|
```sh
|
99
|
-
$
|
100
|
-
|
101
|
-
# or optionally with arguments:
|
102
|
-
|
103
|
-
$ rails generate shopify_app:install
|
47
|
+
$ bundle add shopify_app
|
104
48
|
```
|
105
49
|
|
106
|
-
|
107
|
-
* `application_name` - the name of your app, it can be supplied with or without double-quotes if a whitespace is present. (e.g. `--application_name Example App` or `--application_name "Example App"`)
|
108
|
-
* `scope` - the Oauth access scope required for your app, eg **read_products, write_orders**. *Multiple options* need to be delimited by a comma-space, and can be supplied with or without double-quotes
|
109
|
-
(e.g. `--scope read_products, write_orders, write_products` or `--scope "read_products, write_orders, write_products"`)
|
110
|
-
For more information, refer the [docs](http://docs.shopify.com/api/tutorials/oauth).
|
111
|
-
* `embedded` - the default is to generate an [embedded app](http://docs.shopify.com/embedded-app-sdk), if you want a legacy non-embedded app then set this to false, `--embedded false`
|
112
|
-
|
113
|
-
You can update any of these settings later on easily, the arguments are simply for convenience.
|
114
|
-
|
115
|
-
The generator adds ShopifyApp and the required initializers to the host Rails application.
|
116
|
-
|
117
|
-
After running the `install` generator, you can start your app with `bundle exec rails server` and install your app by visiting localhost.
|
50
|
+
3. Create a `.env` file in the root of `my_shopify_app` to specify your Shopify API credentials:
|
118
51
|
|
119
|
-
|
120
|
-
### Home Controller Generator
|
121
|
-
|
122
|
-
```sh
|
123
|
-
$ rails generate shopify_app:home_controller
|
124
52
|
```
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
### App Proxy Controller Generator
|
130
|
-
|
131
|
-
```sh
|
132
|
-
$ rails generate shopify_app:app_proxy_controller
|
53
|
+
SHOPIFY_API_KEY=<Your Shopify API key>
|
54
|
+
SHOPIFY_API_SECRET=<Your Shopify API secret>
|
133
55
|
```
|
134
56
|
|
135
|
-
|
57
|
+
> In a development environment, you can use a gem like `dotenv-rails` to manage environment variables.
|
136
58
|
|
137
|
-
|
59
|
+
4. Run the default Shopify App generator to create an app that can be embedded in the Shopify Admin:
|
138
60
|
|
139
61
|
```sh
|
140
|
-
$ rails generate shopify_app
|
141
|
-
```
|
142
|
-
|
143
|
-
This will create a controller with the endpoints required to build a [marketing activities extension](https://help.shopify.com/en/api/embedded-apps/app-extensions/shopify-admin/marketing-activities). The extension will be generated with a base url at `/marketing_activities`, which should also be configured in partners.
|
144
|
-
|
145
|
-
### Controllers, Routes and Views
|
146
|
-
|
147
|
-
The last group of generators are for your convenience if you want to start overriding code included as part of the Rails engine. For example by default the engine provides a simple SessionController, if you run the `rails generate shopify_app:controllers` generator then this code gets copied out into your app so you can start adding to it. Routes and views follow the exact same pattern.
|
148
|
-
|
149
|
-
Mounting the Engine
|
150
|
-
-------------------
|
151
|
-
|
152
|
-
Mounting the Engine will provide the basic routes to authenticating a shop with your application. By default it will provide:
|
153
|
-
|
154
|
-
| Verb | Route | Action |
|
155
|
-
|--------|-------------------------------|------------------------------|
|
156
|
-
|GET |'/login' |Login |
|
157
|
-
|POST |'/login' |Login |
|
158
|
-
|GET |'/auth/shopify/callback' |Authenticate Callback |
|
159
|
-
|GET |'/logout' |Logout |
|
160
|
-
|POST |'/webhooks/:type' |Webhook Callback |
|
161
|
-
|
162
|
-
### Nested Routes
|
163
|
-
|
164
|
-
The engine may also be mounted at a nested route, for example:
|
165
|
-
|
166
|
-
```ruby
|
167
|
-
mount ShopifyApp::Engine, at: '/nested'
|
168
|
-
```
|
169
|
-
|
170
|
-
This will create the Shopify engine routes under the specified subpath. You'll also need to make some updates to your `shopify_app.rb` and `omniauth.rb` initializers. First update the shopify_app initializer to include a custom `root_url` e.g.:
|
171
|
-
|
172
|
-
```ruby
|
173
|
-
ShopifyApp.configure do |config|
|
174
|
-
config.root_url = '/nested'
|
175
|
-
end
|
176
|
-
```
|
177
|
-
|
178
|
-
then update the omniauth initializer to include a custom `callback_path` e.g.:
|
179
|
-
|
180
|
-
```ruby
|
181
|
-
provider :shopify,
|
182
|
-
ShopifyApp.configuration.api_key,
|
183
|
-
ShopifyApp.configuration.secret,
|
184
|
-
scope: ShopifyApp.configuration.scope,
|
185
|
-
callback_path: '/nested/auth/shopify/callback'
|
186
|
-
```
|
187
|
-
|
188
|
-
You may also need to change your `config/routes.rb` to render a view for `/nested`, since this is what will be rendered in the Shopify Admin of any shops that have installed your app. The engine itself doesn't have a view for this, so you'll need something like this:
|
189
|
-
|
190
|
-
```ruby
|
191
|
-
# config/routes.rb
|
192
|
-
Rails.application.routes.draw do
|
193
|
-
root :to => 'something_else#index'
|
194
|
-
get "/nested", to: "home#index"
|
195
|
-
mount ShopifyApp::Engine, at: '/nested'
|
196
|
-
end
|
197
|
-
```
|
198
|
-
|
199
|
-
Finally, note that if you do this, to add your app to a store, you must navigate to `/nested` in order to render the `Enter your shop domain to log in or install this app.` UI.
|
200
|
-
|
201
|
-
### Custom login URL
|
202
|
-
|
203
|
-
While you can customize the login view by creating a `/app/views/shopify_app/sessions/new.html.erb` file, you may also want to customize the URL entirely. You can modify your `shopify_app.rb` initializer to provide a custom `login_url` e.g.:
|
204
|
-
|
205
|
-
```ruby
|
206
|
-
ShopifyApp.configure do |config|
|
207
|
-
config.login_url = 'https://my.domain.com/nested/login'
|
208
|
-
end
|
209
|
-
```
|
210
|
-
|
211
|
-
Authentication
|
212
|
-
--------------
|
213
|
-
|
214
|
-
### ShopifyApp::SessionRepository
|
215
|
-
|
216
|
-
`ShopifyApp::SessionRepository` allows you as a developer to define how your sessions are stored and retrieved for shops. The `SessionRepository` is configured in the `config/initializers/shopify_app.rb` file and can be set to any object that implements `self.store(auth_session, *args)` which stores the session and returns a unique identifier and `self.retrieve(id)` which returns a `ShopifyAPI::Session` for the passed id. These methods are already implemented as part of the `ShopifyApp::SessionStorage` concern, but can be overridden for custom implementation.
|
217
|
-
|
218
|
-
If you only run the install generator then by default you will have an in memory store but it **won't work** on multi-server environments including Heroku. For multi-server environments, implement one of the following token-storage strategies.
|
219
|
-
|
220
|
-
#### Shop-based token storage
|
221
|
-
Storing tokens on the store model means that any user login associated to the store will have equal access levels to whatever the original user granted the app.
|
222
|
-
```sh
|
223
|
-
$ rails generate shopify_app:shop_model
|
224
|
-
```
|
225
|
-
This will generate a shop model which will be the storage for the tokens necessary for authentication.
|
226
|
-
|
227
|
-
#### User-based token storage
|
228
|
-
A more granular control over level of access per user on an app might be necessary, to which the shop-based token strategy is not sufficient. Shopify supports a user-based token storage strategy where a unique token to each user can be managed.
|
229
|
-
```sh
|
230
|
-
$ rails generate shopify_app:user_model
|
231
|
-
```
|
232
|
-
This will generate a user model which will be the storage for the tokens necessary for authentication.
|
233
|
-
|
234
|
-
The current Shopify user will be stored in the rails session at `session[:shopify_user]`
|
235
|
-
|
236
|
-
In this mode, The `self.store(auth_session, *args)` will be invoked with a Shopify User object hash, which is then used to store the token as part of a user record, rather than a store record.
|
237
|
-
|
238
|
-
This will change the type of token that Shopify returns and it will only be valid for a short time. Read more about `Online access` [here](https://help.shopify.com/api/getting-started/authentication/oauth). Note that this means you won't be able to use this token to respond to Webhooks.
|
239
|
-
|
240
|
-
#### Migrating from shop-based to user-based token strategy
|
241
|
-
After running the generator, ensure that configuration settings are successfully changed:
|
242
|
-
|
243
|
-
```ruby
|
244
|
-
# In the `omniauth.rb` initializer:
|
245
|
-
provider :shopify,
|
246
|
-
ShopifyApp.configuration.api_key,
|
247
|
-
ShopifyApp.configuration.secret,
|
248
|
-
scope: ShopifyApp.configuration.scope,
|
249
|
-
per_user_permissions: true
|
250
|
-
|
251
|
-
# In the `shopify_app.rb` initializer:
|
252
|
-
config.session_repository = 'User'
|
253
|
-
config.per_user_tokens = true
|
254
|
-
```
|
255
|
-
|
256
|
-
### Authenticated
|
257
|
-
|
258
|
-
The engine provides a `ShopifyApp::Authenticated` concern which should be included in any controller that is intended to be behind Shopify OAuth. It adds `before_action`s to ensure that the user is authenticated and will redirect to the Shopify login page if not. It is best practice to include this concern in a base controller inheriting from your `ApplicationController`, from which all controllers that require Shopify authentication inherit.
|
259
|
-
|
260
|
-
For backwards compatibility, the engine still provides a controller called `ShopifyApp::AuthenticatedController` which includes the `ShopifyApp::Authenticated` concern. Note that it inherits directly from `ActionController::Base`, so you will not be able to share functionality between it and your application's `ApplicationController`.
|
261
|
-
|
262
|
-
### AfterAuthenticate Job
|
263
|
-
|
264
|
-
If your app needs to perform specific actions after the user is authenticated successfully (i.e. every time a new session is created), ShopifyApp can queue or run a job of your choosing (note that we already provide support for automatically creating Webhooks and Scripttags). To configure the after authenticate job update your initializer as follows:
|
265
|
-
|
266
|
-
```ruby
|
267
|
-
ShopifyApp.configure do |config|
|
268
|
-
config.after_authenticate_job = { job: "Shopify::AfterAuthenticateJob" }
|
269
|
-
end
|
270
|
-
```
|
271
|
-
|
272
|
-
The job can be configured as either a class or a class name string.
|
273
|
-
|
274
|
-
If you need the job to run synchronously add the `inline` flag:
|
275
|
-
|
276
|
-
```ruby
|
277
|
-
ShopifyApp.configure do |config|
|
278
|
-
config.after_authenticate_job = { job: Shopify::AfterAuthenticateJob, inline: true }
|
279
|
-
end
|
280
|
-
```
|
281
|
-
|
282
|
-
We've also provided a generator which creates a skeleton job and updates the initializer for you:
|
283
|
-
|
284
|
-
```
|
285
|
-
bin/rails g shopify_app:add_after_authenticate_job
|
286
|
-
```
|
287
|
-
|
288
|
-
If you want to perform that action only once, e.g. send a welcome email to the user when they install the app, you should make sure that this action is idempotent, meaning that it won't have an impact if run multiple times.
|
289
|
-
|
290
|
-
|
291
|
-
WebhooksManager
|
292
|
-
---------------
|
293
|
-
|
294
|
-
ShopifyApp can manage your app's webhooks for you if you set which webhooks you require in the initializer:
|
295
|
-
|
296
|
-
```ruby
|
297
|
-
ShopifyApp.configure do |config|
|
298
|
-
config.webhooks = [
|
299
|
-
{topic: 'carts/update', address: 'https://example-app.com/webhooks/carts_update'}
|
300
|
-
]
|
301
|
-
end
|
302
|
-
```
|
303
|
-
|
304
|
-
When the oauth callback is completed successfully ShopifyApp will queue a background job which will ensure all the specified webhooks exist for that shop. Because this runs on every oauth callback it means your app will always have the webhooks it needs even if the user uninstalls and re-installs the app.
|
305
|
-
|
306
|
-
ShopifyApp also provides a WebhooksController that receives webhooks and queues a job based on the received topic. For example if you register the webhook from above then all you need to do is create a job called `CartsUpdateJob`. The job will be queued with 2 params: `shop_domain` and `webhook` (which is the webhook body).
|
307
|
-
|
308
|
-
If you would like to namespace your jobs you may set `webhook_jobs_namespace` in the config. For example if your app handles webhooks from other ecommerce applications as well, and you want Shopify cart update webhooks to be processed by a job living in `jobs/shopify/webhooks/carts_update_job.rb` rather than `jobs/carts_update_job.rb`):
|
309
|
-
|
310
|
-
```ruby
|
311
|
-
ShopifyApp.configure do |config|
|
312
|
-
config.webhook_jobs_namespace = 'shopify/webhooks'
|
313
|
-
end
|
314
|
-
```
|
315
|
-
|
316
|
-
If you are only interested in particular fields, you can optionally filter the data sent by Shopify by specifying the `fields` parameter in `config/webhooks`. Note that you will still receive a webhook request from Shopify every time the resource is updated, but only the specified fields will be sent.
|
317
|
-
|
318
|
-
```ruby
|
319
|
-
ShopifyApp.configure do |config|
|
320
|
-
config.webhooks = [
|
321
|
-
{topic: 'products/update', address: 'https://example-app.com/webhooks/products_update', fields: ['title', 'vendor']}
|
322
|
-
]
|
323
|
-
end
|
324
|
-
```
|
325
|
-
|
326
|
-
If you'd rather implement your own controller then you'll want to use the WebhookVerification module to verify your webhooks, example:
|
327
|
-
|
328
|
-
```ruby
|
329
|
-
class CustomWebhooksController < ApplicationController
|
330
|
-
include ShopifyApp::WebhookVerification
|
331
|
-
|
332
|
-
def carts_update
|
333
|
-
params.permit!
|
334
|
-
SomeJob.perform_later(shop_domain: shop_domain, webhook: webhook_params.to_h)
|
335
|
-
head :no_content
|
336
|
-
end
|
337
|
-
|
338
|
-
private
|
339
|
-
|
340
|
-
def webhook_params
|
341
|
-
params.except(:controller, :action, :type)
|
342
|
-
end
|
343
|
-
end
|
344
|
-
```
|
345
|
-
|
346
|
-
The module skips the `verify_authenticity_token` before_action and adds an action to verify that the webhook came from Shopify. You can now add a post route to your application pointing to the controller and action to accept the webhook data from Shopify.
|
347
|
-
|
348
|
-
The WebhooksManager uses ActiveJob, if ActiveJob is not configured then by default Rails will run the jobs inline. However it is highly recommended to configure a proper background processing queue like sidekiq or resque in production.
|
349
|
-
|
350
|
-
ShopifyApp can create webhooks for you using the `add_webhook` generator. This will add the new webhook to your config and create the required job class for you.
|
351
|
-
|
352
|
-
```
|
353
|
-
rails g shopify_app:add_webhook -t carts/update -a https://example.com/webhooks/carts_update
|
354
|
-
```
|
355
|
-
|
356
|
-
where `-t` is the topic and `-a` is the address the webhook should be sent to.
|
357
|
-
|
358
|
-
ScripttagsManager
|
359
|
-
-----------------
|
360
|
-
|
361
|
-
As with webhooks, ShopifyApp can manage your app's scripttags for you by setting which scripttags you require in the initializer:
|
362
|
-
|
363
|
-
```ruby
|
364
|
-
ShopifyApp.configure do |config|
|
365
|
-
config.scripttags = [
|
366
|
-
{event:'onload', src: 'https://my-shopifyapp.herokuapp.com/fancy.js'},
|
367
|
-
{event:'onload', src: ->(domain) { dynamic_tag_url(domain) } }
|
368
|
-
]
|
369
|
-
end
|
370
|
-
```
|
371
|
-
|
372
|
-
You also need to have write_script_tags permission in the config scope in order to add script tags automatically:
|
373
|
-
|
374
|
-
```ruby
|
375
|
-
config.scope = '... , write_script_tags'
|
376
|
-
```
|
377
|
-
|
378
|
-
Scripttags are created in the same way as the Webhooks, with a background job which will create the required scripttags.
|
379
|
-
|
380
|
-
If `src` responds to `call` its return value will be used as the scripttag's source. It will be called on scripttag creation and deletion.
|
381
|
-
|
382
|
-
RotateShopifyTokenJob
|
383
|
-
---------------------
|
384
|
-
|
385
|
-
If your Shopify secret key is leaked, you can use the RotateShopifyTokenJob to perform [API Credential Rotation](https://help.shopify.com/en/api/getting-started/authentication/oauth/api-credential-rotation).
|
386
|
-
|
387
|
-
Before running the job, you'll need to generate a new secret key from your Shopify Partner dashboard, and update the `/config/initializers/shopify_app.rb` to hold your new and old secret keys:
|
388
|
-
|
389
|
-
```ruby
|
390
|
-
config.secret = Rails.application.secrets.shopify_secret
|
391
|
-
config.old_secret = Rails.application.secrets.old_shopify_secret
|
62
|
+
$ rails generate shopify_app
|
392
63
|
```
|
393
64
|
|
394
|
-
|
65
|
+
5. Run a migration to create the necessary tables in your database:
|
395
66
|
|
396
67
|
```sh
|
397
|
-
|
68
|
+
$ rails db:migrate
|
398
69
|
```
|
399
70
|
|
400
|
-
|
401
|
-
|
402
|
-
⚠️ Note: if you are updating `shopify_app` from a version prior to 8.4.2 (and do not wish to run the default/install generator again), you will need to add [the following line](https://github.com/Shopify/shopify_app/blob/4f7e6cca2a472d8f7af44b938bd0fcafe4d8e88a/lib/generators/shopify_app/install/templates/shopify_provider.rb#L18) to `config/intializers/omniauth.rb`:
|
403
|
-
|
404
|
-
```ruby
|
405
|
-
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
|
406
|
-
```
|
407
|
-
|
408
|
-
App Tunneling
|
409
|
-
-------------
|
410
|
-
|
411
|
-
Your local app needs to be accessible from the public Internet in order to install it on a Shopify store, to use the [App Proxy Controller](#app-proxy-controller-generator) or receive Webhooks.
|
412
|
-
|
413
|
-
Use a tunneling service like [ngrok](https://ngrok.com/), [Forward](https://forwardhq.com/), [Beeceptor](https://beeceptor.com/), [Mockbin](http://mockbin.org/), or [Hookbin](https://hookbin.com/) to make your development environment accessible to the internet.
|
414
|
-
|
415
|
-
For example with [ngrok](https://ngrok.com/), run this command to set up a tunnel proxy to Rails' default port:
|
71
|
+
6. Run the app:
|
416
72
|
|
417
73
|
```sh
|
418
|
-
|
74
|
+
$ rails server
|
419
75
|
```
|
420
76
|
|
421
|
-
|
422
|
-
--------------------
|
77
|
+
See [*Quickstart*](/docs/Quickstart.md) to learn how to install your app on a shop.
|
423
78
|
|
424
|
-
|
79
|
+
This app implements [OAuth 2.0](https://shopify.dev/tutorials/authenticate-with-oauth) with Shopify to authenticate requests made to Shopify APIs. By default, this app is configured to use [session tokens](https://shopify.dev/concepts/apps/building-embedded-apps-using-session-tokens) to authenticate merchants when embedded in the Shopify Admin.
|
425
80
|
|
426
|
-
|
81
|
+
See [*Generators*](/docs/shopify_app/generators.md) for a complete list of generators available to Shopify App.
|
427
82
|
|
428
|
-
|
429
|
-
Additional controllers for resources within the App_Proxy namespace, will need to include the mixin like so:
|
83
|
+
## Documentation
|
430
84
|
|
431
|
-
|
432
|
-
# app/controllers/app_proxy/reviews_controller.rb
|
433
|
-
class ReviewsController < ApplicationController
|
434
|
-
include ShopifyApp::AppProxyVerification
|
435
|
-
# ...
|
436
|
-
end
|
437
|
-
```
|
438
|
-
|
439
|
-
Create your app proxy url in the [Shopify Partners' Dashboard][dashboard], making sure to point it to `https://your_app_website.com/app_proxy`.
|
440
|
-
![Creating an App Proxy](/images/app-proxy-screenshot.png)
|
441
|
-
|
442
|
-
App Bridge
|
443
|
-
---
|
85
|
+
You can find documentation on gem usage, concepts, mixins, installation, and more in [`/docs`](/docs).
|
444
86
|
|
445
|
-
|
87
|
+
* Start with the [*Generators*](/docs/shopify_app/generators.md) document to learn more about the generators this gem offers.
|
88
|
+
* Check out the [*Changelog*](/CHANGELOG.md) for notes on the latest gem releases.
|
89
|
+
* See [*Troubleshooting*](/docs/Troubleshooting.md) for tips on common issues.
|
90
|
+
* If you are looking to upgrade your Shopify App version to a new major release, see [*Upgrading*](/docs/Upgrading.md) for important notes on breaking changes.
|
446
91
|
|
447
|
-
|
448
|
-
---------------
|
92
|
+
### Overview
|
449
93
|
|
450
|
-
|
94
|
+
[Quickstart](/docs/Quickstart.md)
|
451
95
|
|
452
|
-
|
453
|
-
-------------------------------------------------
|
96
|
+
[Troubleshooting](/docs/Troubleshooting.md)
|
454
97
|
|
455
|
-
|
456
|
-
|
457
|
-
```javascript
|
458
|
-
forceRedirect: <%= Rails.env.development? || Rails.env.test? ? 'false' : 'true' %>
|
459
|
-
```
|
98
|
+
[Upgrading](/docs/Upgrading.md)
|
460
99
|
|
461
|
-
|
462
|
-
|
100
|
+
[Shopify App](/docs/shopify_app)
|
101
|
+
* [Authentication](/docs/shopify_app/authentication.md)
|
102
|
+
* [Engine](/docs/shopify_app/engine.md)
|
103
|
+
* [Generators](/docs/shopify_app/generators.md)
|
104
|
+
* [ScriptTags](/docs/shopify_app/script-tags.md)
|
105
|
+
* [Session repository](/docs/shopify_app/session-repository.md)
|
106
|
+
* [Handling changes in access scopes](/docs/shopify_app/handling-access-scopes-changes.md)
|
107
|
+
* [Testing](/docs/shopify_app/testing.md)
|
108
|
+
* [Webhooks](/docs/shopify_app/webhooks.md)
|
463
109
|
|
464
|
-
|
465
|
-
- [Read the docs!](https://help.shopify.com/api/guides)
|
110
|
+
### Engine
|
466
111
|
|
467
|
-
|
468
|
-
---------------------------
|
112
|
+
Mounting the Shopify App Rails Engine provides the following routes. These routes are configured to help install your application on shops and implement OAuth.
|
469
113
|
|
470
|
-
|
471
|
-
|
114
|
+
| Verb | Route | Action |
|
115
|
+
| ---: | :--- | :--- |
|
116
|
+
| `GET` | `/login` | Login |
|
117
|
+
| `POST` | `/login` | Login |
|
118
|
+
| `GET` | `/auth/shopify/callback` | OAuth redirect URI |
|
119
|
+
| `GET` | `/logout` | Logout |
|
120
|
+
| `POST` | `/webhooks/:type` | Webhook callback |
|
472
121
|
|
473
|
-
Rails
|
474
|
-
---------------------
|
122
|
+
These routes are configurable. See the more detailed [*Engine*](/docs/shopify_app/engine.md) documentation to learn how you can customize the login URL or mount the Shopify App Rails engine at nested routes.
|
475
123
|
|
476
|
-
|
477
|
-
If you are using sprockets in rails 6 or want to generate a shopify_app without webpacker run the install task by running
|
478
|
-
|
479
|
-
```
|
480
|
-
SHOPIFY_APP_DISABLE_WEBPACKER=1 rails generate shopify_app
|
481
|
-
```
|
482
|
-
|
483
|
-
and then in your ShopifyApp configuration block, add
|
484
|
-
|
485
|
-
```
|
486
|
-
ShopifyApp.configure do |config|
|
487
|
-
config.disable_webpacker = true
|
488
|
-
end
|
489
|
-
```
|
490
|
-
|
491
|
-
Upgrading from 8.6 to 9.0.0
|
492
|
-
---------------------------
|
493
|
-
|
494
|
-
### Configuration change
|
495
|
-
|
496
|
-
Add an api version configuration in `config/initializers/shopify_app.rb`
|
497
|
-
Set this to the version you want to run against by default. See [Shopify API docs](https://help.shopify.com/en/api/versioning) for versions available.
|
498
|
-
```ruby
|
499
|
-
config.api_version = '2019-04'
|
500
|
-
```
|
501
|
-
|
502
|
-
### Session storage change
|
503
|
-
|
504
|
-
You will need to add an `api_version` method to you session storage object. The default implementation for this is.
|
505
|
-
```ruby
|
506
|
-
def api_version
|
507
|
-
ShopifyApp.configuration.api_version
|
508
|
-
end
|
509
|
-
```
|
510
|
-
|
511
|
-
### Generated file change
|
512
|
-
|
513
|
-
`embedded_app.html.erb` the usage of `shop_session.url` needs to be changed to `shop_session.domain`
|
514
|
-
```erb
|
515
|
-
<script type="text/javascript">
|
516
|
-
ShopifyApp.init({
|
517
|
-
apiKey: "<%= ShopifyApp.configuration.api_key %>",
|
518
|
-
|
519
|
-
shopOrigin: "<%= "https://#{ @shop_session.url }" if @shop_session %>",
|
520
|
-
|
521
|
-
debug: false,
|
522
|
-
forceRedirect: true
|
523
|
-
});
|
524
|
-
</script>
|
525
|
-
```
|
526
|
-
is changed to
|
527
|
-
```erb
|
528
|
-
<script type="text/javascript">
|
529
|
-
ShopifyApp.init({
|
530
|
-
apiKey: "<%= ShopifyApp.configuration.api_key %>",
|
531
|
-
|
532
|
-
shopOrigin: "<%= "https://#{ @shop_session.domain }" if @shop_session %>",
|
533
|
-
|
534
|
-
debug: false,
|
535
|
-
forceRedirect: true
|
536
|
-
});
|
537
|
-
</script>
|
538
|
-
```
|
124
|
+
To learn more about how this gem authenticates with Shopify, see [*Authentication*](/docs/shopify_app/authentication.md).
|
539
125
|
|
540
|
-
###
|
126
|
+
### API Versioning
|
541
127
|
|
542
|
-
|
128
|
+
[Shopify's API is versioned](https://shopify.dev/concepts/about-apis/versioning). With Shopify App `v1.11.0`, the included Shopify API gem allows developers to specify and update the Shopify API version they want their app or service to use. The Shopify API gem also surfaces warnings to Rails apps about [deprecated endpoints, GraphQL fields and more](https://shopify.dev/concepts/about-apis/versioning#deprecation-practices).
|
543
129
|
|
544
|
-
[
|
545
|
-
[app-bridge]:https://help.shopify.com/en/api/embedded-apps/app-bridge
|
130
|
+
See the [Shopify API gem README](https://github.com/Shopify/shopify_api/) for more information.
|