loopstak-shopify-sinatra-app 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8b42b5ddb8de2cb8697c6a271c23e08d458241634be23ab6cd5149af43d66e28
4
+ data.tar.gz: ff46cfa7de389cadefc54644848fe7efea220ddec8b849ab75aab56ab1dc2bd3
5
+ SHA512:
6
+ metadata.gz: d5dd5d69945f3f6926869d4282661f7b8cb9f348de05570dd6c2ed8624db85651d35e4bfdc64057568a72c0742030e779b35289ca08d01c91d3156bda41489ee
7
+ data.tar.gz: 84558667eae51f1834857ae62e54e379c31592e702df69382b503cd76080d93c714e4d1a6ef169e3c4d46dc145bed06a7342e98bc2e0a42f1d0eefafc9fe77a3
@@ -0,0 +1,52 @@
1
+ 0.8.0
2
+ -----
3
+ * Shopify updated the way sessions are created: https://github.com/Shopify/shopify_api/blob/master/README.md#-breaking-change-notice-for-version-700-, updating code to reflect these changes.
4
+
5
+ 0.7.0
6
+ -----
7
+ * make base_url private (users can add back in their app easily if needed)
8
+ * store request params in the session so they can be retrieved after the omniauth flow. This fixes app actions from the admin if the user's session has expired
9
+ * refactored some smaller methods to make the shopify_session method easier on the eyes.
10
+
11
+ 0.6.0
12
+ -----
13
+ * remove current_shop* methods in favor of yielding shop_name to the block methods
14
+
15
+ 0.5.0
16
+ -----
17
+ * replace webhook_session and webhook_job with shopify_webhook
18
+ * remove redis and resque as dependencies
19
+
20
+ 0.4.0
21
+ -----
22
+ * update to sinatra 2.0.1
23
+ * update to attr_encrypted 3.1.0
24
+ * remove SHOPIFY_REDIRECT_URI param
25
+
26
+ 0.3.4
27
+ -----
28
+ * rename lib to src in the example/template
29
+
30
+ 0.3.3
31
+ -----
32
+ * fix a bug in the generator
33
+
34
+ 0.3.2
35
+ -----
36
+ * remove an extra `%` from the redirect view
37
+
38
+ 0.3.1
39
+ -----
40
+ * update authentication code for upcoming chrome changes.
41
+
42
+ 0.3.0
43
+ -----
44
+ * Remove sinatra-twitter-bootstrap dependency. Include css from cdn directly for example app.
45
+
46
+ 0.2.0
47
+ -----
48
+ * added a SHOPIFY_REDIRECT_URI env param for setting the redirect_uri (was breifly HOSTNAME)
49
+ * add versions to gemfile
50
+ * refactored the generator
51
+ * Changed install method to after_shopify_auth. Implementations of this method must now be idempotent as this will be called anytime the app is auth'd which may be due to just a lost session and not necessarily an install.
52
+ * Always redo the full auth rather than trying to keep track of first time install state vs re-auth
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,114 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ loopstak-shopify-sinatra-app (1.0.0)
5
+ activesupport
6
+ attr_encrypted (~> 3.1.0)
7
+ omniauth-shopify-oauth2
8
+ rack-flash3 (~> 1.0.5)
9
+ shopify_api (>= 7.0.1, < 9.1.0)
10
+ sinatra (~> 2.0.2)
11
+ sinatra-activerecord (~> 2.0.9)
12
+
13
+ GEM
14
+ remote: https://rubygems.org/
15
+ specs:
16
+ activemodel (6.0.2.1)
17
+ activesupport (= 6.0.2.1)
18
+ activemodel-serializers-xml (1.0.2)
19
+ activemodel (> 5.x)
20
+ activesupport (> 5.x)
21
+ builder (~> 3.1)
22
+ activerecord (6.0.2.1)
23
+ activemodel (= 6.0.2.1)
24
+ activesupport (= 6.0.2.1)
25
+ activeresource (5.1.0)
26
+ activemodel (>= 5.0, < 7)
27
+ activemodel-serializers-xml (~> 1.0)
28
+ activesupport (>= 5.0, < 7)
29
+ activesupport (6.0.2.1)
30
+ concurrent-ruby (~> 1.0, >= 1.0.2)
31
+ i18n (>= 0.7, < 2)
32
+ minitest (~> 5.1)
33
+ tzinfo (~> 1.1)
34
+ zeitwerk (~> 2.2)
35
+ attr_encrypted (3.1.0)
36
+ encryptor (~> 3.0.0)
37
+ builder (3.2.4)
38
+ concurrent-ruby (1.1.5)
39
+ encryptor (3.0.0)
40
+ fakeweb (1.3.0)
41
+ faraday (1.0.0)
42
+ multipart-post (>= 1.2, < 3)
43
+ graphql (1.10.1)
44
+ graphql-client (0.16.0)
45
+ activesupport (>= 3.0)
46
+ graphql (~> 1.8)
47
+ hashie (3.6.0)
48
+ i18n (1.8.2)
49
+ concurrent-ruby (~> 1.0)
50
+ jwt (2.2.1)
51
+ minitest (5.14.0)
52
+ mocha (1.11.2)
53
+ multi_json (1.14.1)
54
+ multi_xml (0.6.0)
55
+ multipart-post (2.1.1)
56
+ mustermann (1.1.1)
57
+ ruby2_keywords (~> 0.0.1)
58
+ oauth2 (1.4.3)
59
+ faraday (>= 0.8, < 2.0)
60
+ jwt (>= 1.0, < 3.0)
61
+ multi_json (~> 1.3)
62
+ multi_xml (~> 0.5)
63
+ rack (>= 1.2, < 3)
64
+ omniauth (1.9.0)
65
+ hashie (>= 3.4.6, < 3.7.0)
66
+ rack (>= 1.6.2, < 3)
67
+ omniauth-oauth2 (1.5.0)
68
+ oauth2 (~> 1.1)
69
+ omniauth (~> 1.2)
70
+ omniauth-shopify-oauth2 (2.2.0)
71
+ activesupport
72
+ omniauth-oauth2 (~> 1.5.0)
73
+ rack (2.1.2)
74
+ rack-flash3 (1.0.5)
75
+ rack
76
+ rack-protection (2.0.8.1)
77
+ rack
78
+ rack-test (1.1.0)
79
+ rack (>= 1.0, < 3)
80
+ rake (13.0.1)
81
+ ruby2_keywords (0.0.2)
82
+ shopify_api (9.0.0)
83
+ activeresource (>= 4.1.0, < 6.0.0)
84
+ graphql-client
85
+ rack
86
+ sinatra (2.0.8.1)
87
+ mustermann (~> 1.0)
88
+ rack (~> 2.0)
89
+ rack-protection (= 2.0.8.1)
90
+ tilt (~> 2.0)
91
+ sinatra-activerecord (2.0.14)
92
+ activerecord (>= 3.2)
93
+ sinatra (>= 1.0)
94
+ sqlite3 (1.4.2)
95
+ thread_safe (0.3.6)
96
+ tilt (2.0.10)
97
+ tzinfo (1.2.6)
98
+ thread_safe (~> 0.1)
99
+ zeitwerk (2.2.2)
100
+
101
+ PLATFORMS
102
+ ruby
103
+
104
+ DEPENDENCIES
105
+ fakeweb
106
+ loopstak-shopify-sinatra-app!
107
+ minitest
108
+ mocha
109
+ rack-test
110
+ rake
111
+ sqlite3
112
+
113
+ BUNDLED WITH
114
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Kevin Hughes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,228 @@
1
+ shopify-sinatra-app [![Build Status](https://travis-ci.org/kevinhughes27/shopify-tax-receipts.svg)](https://travis-ci.org/kevinhughes27/shopify-sinatra-app)
2
+ ===================
3
+
4
+ "A classy shopify app"
5
+
6
+ shopify-sinatra-app is lightweight extension for building Shopify apps using Sinatra. It comes with the Shopify API gem for interacting with the Shopify API and uses the Shopify omniauth gem to handle authentication via Oauth (other auth methods are not supported). The framework itself provides a handful of helper methods to make creating your app as easy as possible. The framework was designed with deployment to Heroku in mind and following the instructions below I've been able to create a new application from scratch, deploy it to Heroku and install on my live test shop in less than 5 minutes.
7
+
8
+
9
+ Getting Started
10
+ ---------------
11
+
12
+ Install the gem:
13
+
14
+ ```
15
+ gem install shopify-sinatra-app
16
+ ```
17
+
18
+ or build from source
19
+
20
+ ```
21
+ gem build shopify-sinatra-app.gemspec
22
+ gem install shopify-sinatra-app-X.X.X.gem
23
+ ```
24
+
25
+ To create a new app use the generator:
26
+
27
+ ```
28
+ shopify-sinatra-app-generator new <your new app name>
29
+ ```
30
+
31
+ This will create a new skeleton shopify-sinatra-app. The generator will create several default files for you rather than having them bundled in the sinatra extension - its worthwhile to read this section to understand what each of these files is for.
32
+
33
+ `config/database.yml` --> The database config for active record. Initially this is setup to use sqlite3 for development and testing which you may want to change to mimic your production database.
34
+
35
+ `.gitignore` --> tells git which files to ignore, namely `.env` you may find more things you want to add to this file.
36
+
37
+ `.env` --> a hidden file not tracked by source control for storing credentials etc. to be set as environment variables
38
+
39
+ `config.ru` --> Rackup file - describes how to run a rack based app
40
+
41
+ `Gemfile` --> manages the dependencies of the app
42
+
43
+ `src/app.rb` --> This file is the skeleton app file. More details on how to use the methods provided by this extension are given in the following section. There are more comments inside this file explaining the skeleton app.
44
+
45
+ `Procfile` --> Specific for deploying to Heroku, this file tells heroku how to run the app
46
+
47
+ `public/icon.png` --> This icon file is used by the Shopify Embedded App SKD and is shown in the menu bar of your embedded app
48
+
49
+ `Rakefile` --> includes some helper methods etc for running and managing the app. Standard for ruby based projects
50
+
51
+ `views/layouts/appliction.erb` --> This is the layout file that all templates will use unless otherwise specified. It sets up some defaults for using the Shopify Embedded App SDK and Twitter Bootstrap for styling
52
+
53
+ `views/_top_bar.erb` --> This is a partial view that describes the top bar inside a Shopify Embedded App. It also has some code to *forward* flash messages to the Embedded App SKD
54
+
55
+ `views/*` --> The other views used by the app. You'll probably make a lot of changes to home.erb and install.erb to customize the experience for your app
56
+
57
+ `test/*` --> Test files, fixtures and helpers for testing your app.
58
+
59
+ ### Setting the app to use your Shopify API credentials
60
+
61
+ You'll need to create a Shopify Partner Account and a new application. You can make an account [here](http://www.shopify.ca/partners) and see this [tutorial](http://docs.shopify.com/api/the-basics/getting-started) for creating a new application. This app uses the default redirect_uri from omniauth `<your domain>/auth/shopify/callback` so set it accordingly when creating your app.
62
+
63
+ Note - The shopify-sinatra-app creates an embedded app! You need change the embedded setting to `enabled` in the [Shopify Partner area](https://app.shopify.com/services/partners/api_clients) for your app. If you don't want your app to be embedded then remove the related code in `layout/application.erb` and delete the `layout/_top_bar.erb` file and the references to it in the other views.
64
+
65
+ After creating your new application you need to edit the `.env` file and add the following lines:
66
+
67
+ ```
68
+ SHOPIFY_API_KEY=<your api key>
69
+ SHOPIFY_SHARED_SECRET=<your shared secret>
70
+ SECRET=<generate a random string to encrypt credentials with>
71
+ ```
72
+
73
+ If your app has any other secret credentials you should add them to this file.
74
+
75
+
76
+ Shopify::Methods
77
+ ----------------
78
+
79
+ **shopify_session** - The main method of the framework, most of your routes will use this method to acquire a valid shopify session and then perform api calls to Shopfiy. The method activates a Shopify API session for you and accepts a block inside of which you can use the ShopifyAPI. Here is an example endpoint that displays products:
80
+
81
+ ```ruby
82
+ get '/products.json' do
83
+ shopify_session do |shop_name|
84
+ products = ShopifyAPI::Product.all(limit: 5)
85
+ products.to_json
86
+ end
87
+ end
88
+ ```
89
+
90
+ **shopify_webhook** - This method is for an endpoint that receives a webhook from Shopify. Webhooks are a great way to keep your app in sync with a shop's data without polling. You can read more about webhooks [here](http://docs.shopify.com/api/tutorials/using-webhooks). This method also takes a block and yields the `shop_name` and `webhook_body` as a hash (note only works for json webhooks, don't use xml). Here is an example that listens to an order creation webhook:
91
+
92
+ ```ruby
93
+ post '/order.json' do
94
+ shopify_webhook do |shop_name, webhook_data|
95
+ # do something with the data
96
+ end
97
+ end
98
+ ```
99
+
100
+ Note this method does not active a Shopify session by default but the current_shop* methods still work. It is not advised but if you want to handle the webhook in a web request you will need to activate the ShopifyAPI session manually:
101
+
102
+ ```ruby
103
+ shop = Shop.find_by(name: current_shop_name)
104
+ api_session = ShopifyAPI::Session.new(shop.name, shop.token)
105
+ ShopifyAPI::Base.activate_session(api_session)
106
+ ```
107
+
108
+ It's impossible to control the flow of webhooks to your app from Shopify especially if a larger store installs your app or if a shop has a flash sale. To prevent your app from getting overloaded with webhook requests it is best practise to process webhooks in a background queue and return a `200` to Shopify immediately. Ruby has several good background job frameworks that work with Sinatra including [Sidekiq](https://github.com/mperham/sidekiq) and [Resque](https://github.com/resque/resque).
109
+
110
+
111
+ **after_shopify_auth** - This is a private method provided with the framework that gets called whenever the app is authorized. You should fill this method in with anything you need to initialize, for example webhooks and services on Shopify or any other database models you have created specific to a shop. Note that this method will be called anytime the auth flow is completed so this method should be idempotent (running it twice has the same effect as running it once).
112
+
113
+ **logout** - This method clears the current session
114
+
115
+ shopify-sinatra-app includes sinatra/activerecord for creating models that can be persisted in the database. You might want to read more about sinatra/activerecord and the methods it makes available to you: [https://github.com/janko-m/sinatra-activerecord](https://github.com/janko-m/sinatra-activerecord)
116
+
117
+ shopify-sinatra-app also includes `rack-flash3` and the flash messages are forwarded to the Shopify Embedded App SDK (see the code in `views/layouts/application.erb`). Flash messages are useful for signalling to your users that a request was successful without changing the page. The following is an example of how to use a flash message in a route:
118
+
119
+ ```ruby
120
+ post '/flash_message' do
121
+ flash[:notice] = "Flash Message!"
122
+ redirect '/'
123
+ end
124
+ ```
125
+
126
+ note - a flash must be followed by a redirect or it won't work!
127
+
128
+
129
+ Developing
130
+ ----------
131
+ The embedded app sdk won't load non https content so you'll need to use a forwarding service like [ngrok](https://ngrok.com/) or [forwardhq](https://forwardhq.com/). Set your application url in the [Shopify Partner area](https://app.shopify.com/services/partners/api_clients) to your forwarded url. However The redirect_uri should still be `http://localhost:4567/auth/shopify/callback` which will allow you to install your app on a live shop while running it locally.
132
+
133
+ To run the app locally we use `foreman` which comes with the [Heroku Toolbelt](https://devcenter.heroku.com/articles/quickstart). Foreman handles running our application and setting our credentials as environment variables. To run the application type:
134
+
135
+ ```
136
+ PORT=4567 foreman run web
137
+ ```
138
+
139
+ Note - we use `foreman run ...` not `foreman start ...` because we only want to start the single process that is our app. This means if you add a debugger in your app it will trigger properly in the command line when the debugger is hit. If you don't have any debuggers feel free to use `foreman start -p 4567`.
140
+
141
+ To debug your app simply add `require 'byebug'` at the top and then type `byebug` where you would like to drop into an interactive session. You may also want to try out [Pry](http://pryrepl.org/).
142
+
143
+ If you are testing webhooks locally make sure they also go through the forwarded url and not `localhost`.
144
+
145
+
146
+ Testing
147
+ -------
148
+
149
+ Some basic tests are included in the generated app. To run them simply run:
150
+
151
+ ```
152
+ bundle exec rake test:prepare
153
+ bundle exec rake test
154
+ ```
155
+
156
+ `test:prepare` will initialize your testing database using the `seeds.rb` file. If you have added additional models you can add them here.
157
+
158
+ Checkout the contents of the `app_test.rb` file and the `test_helper.rb` and modify them as you add functionality to your app. You can also check the tests of other apps using this framework to see more about how to write tests for your own app.
159
+
160
+
161
+ Deploying
162
+ ---------
163
+
164
+ This template was created with deploying to Heroku in mind. Heroku is a cloud based app hosting provider that makes it easy to get an application into a product environment.
165
+
166
+ Before you can get started with Heroku you need to create a git repo for you application:
167
+
168
+ ```
169
+ git init
170
+ git add .
171
+ git commit -m "initial commit"
172
+ ```
173
+
174
+ Now you can create a new heroku application. Download the [Heroku Toolbelt](https://devcenter.heroku.com/articles/quickstart) and run the following command to create a new application:
175
+
176
+ ```
177
+ heroku apps:create <your new app name>
178
+ ```
179
+
180
+ You will also need to add the following (free) add-ons to your new Heroku app:
181
+
182
+ ```
183
+ heroku addons:add heroku-postgresql
184
+ ```
185
+
186
+ Now we can deploy the new application to Heroku. Deploying to Heroku is as simple as pushing the code using git:
187
+
188
+ ```
189
+ git push heroku master
190
+ ```
191
+
192
+ A `rake deploy2heroku` command is included in the generated Rakefile which does just this.
193
+
194
+ Now that our application is deployed we need to run `rake db:migrate` to initialize our database on Heroku. To do this run:
195
+
196
+ ```
197
+ heroku run rake db:migrate
198
+ ```
199
+
200
+ We also need to set our environment variables on Heroku. The environment variables are stored in `.env` and are not tracked by git. This is to protect your credentials in the case of a source control breach. Heroku provides a command to set environment variables: `heroku config:set VAR=foo`. In the generated Rakefile there is a helper method that will properly set all the variables in your `.env` file:
201
+
202
+ ```
203
+ rake creds2heroku
204
+ ```
205
+
206
+ and make sure you have at least 1 dyno for web:
207
+
208
+ ```
209
+ heroku scale web=1
210
+ ```
211
+
212
+ Make sure you set your shopify apps url to your Heroku app url (and make sure to use the `https` version or else the Embedded App SDK won't work) in the Shopify Partner area https://app.shopify.com/services/partners/api_clients.
213
+
214
+
215
+ Apps using this framework
216
+ -------------------------
217
+
218
+ * [shopify-fulfillment-integration](https://github.com/Shopify/shopify-fulfillment-integration)
219
+ * [shopify-tax-receipts](https://github.com/pickle27/shopify-tax-receipts)
220
+ * Add yours!
221
+
222
+
223
+ Contributing
224
+ ------------
225
+
226
+ PRs welcome!
227
+
228
+ Note - this framework does have tests! They are the same tests that get generated for new apps by the generator. You can run them with `./test.sh`
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+
4
+ class Generator
5
+ attr_reader :spec, :app_dir, :example_dir
6
+
7
+ def initialize(app_name)
8
+ @spec = Gem::Specification.find_by_name('shopify-sinatra-app')
9
+ gem_root = spec.gem_dir
10
+ @example_dir = gem_root + '/example'
11
+
12
+ working_dir = Dir.pwd
13
+ @app_dir = working_dir + '/' + app_name
14
+
15
+ log "Generating new app: #{app_name}"
16
+ log "fullpath: #{app_dir}"
17
+ end
18
+
19
+ def run
20
+ if Dir.exists? app_dir
21
+ log 'App directory alread exists, pick a new app name or delete the existing folder'
22
+ return
23
+ end
24
+
25
+ copy_example_app
26
+ create_dot_env
27
+ sub_latest_version
28
+ bundle_install
29
+ migrate_database
30
+ end
31
+
32
+ private
33
+
34
+ def copy_example_app
35
+ FileUtils.cp_r(example_dir, app_dir)
36
+ end
37
+
38
+ def create_dot_env
39
+ FileUtils.touch(app_dir + '/.env')
40
+ file = File.open(app_dir + '/.env', 'w')
41
+ file.write("SHOPIFY_API_KEY=your_api_key\n")
42
+ file.write("SHOPIFY_SHARED_SECRET=your_shared_secret\n")
43
+ file.write("SECRET=random_string_to_encrypt_credentials_with\n")
44
+ file.close
45
+ end
46
+
47
+ def sub_latest_version
48
+ file_name = "#{app_dir}/Gemfile"
49
+ text = File.read(file_name)
50
+ new_contents = text.gsub("gem 'shopify-sinatra-app', path: '../'", "gem 'shopify-sinatra-app', '~> #{spec.version}'")
51
+ File.open(file_name, "w") {|file| file.puts new_contents }
52
+ end
53
+
54
+ def bundle_install
55
+ Dir.chdir(app_dir)
56
+
57
+ pipe = IO.popen('bundle install')
58
+ while (line = pipe.gets)
59
+ print line
60
+ end
61
+ end
62
+
63
+ def migrate_database
64
+ Dir.chdir(app_dir)
65
+
66
+ pipe = IO.popen('bundle exec rake db:migrate')
67
+ while (line = pipe.gets)
68
+ print line
69
+ end
70
+ end
71
+
72
+ def log(msg)
73
+ puts msg
74
+ end
75
+ end
76
+
77
+ if ARGV.length < 2
78
+ puts "Usage:\nshopify-sinatra-app-generator new <app_name>"
79
+ else
80
+ app_name = ARGV[1]
81
+ Generator.new(app_name).run
82
+ end