shopify_api 3.1.8 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +32 -0
- data/CHANGELOG +14 -2
- data/Gemfile.lock +2 -2
- data/Gemfile_ar30 +9 -0
- data/Gemfile_ar31 +9 -0
- data/Gemfile_ar32 +9 -0
- data/README.rdoc +18 -15
- data/lib/active_resource/base_ext.rb +14 -15
- data/lib/active_resource/disable_prefix_check.rb +14 -0
- data/lib/active_resource/json_errors.rb +14 -4
- data/lib/active_resource/to_query.rb +10 -0
- data/lib/shopify_api.rb +1 -0
- data/lib/shopify_api/resources.rb +1 -1
- data/lib/shopify_api/resources/base.rb +4 -0
- data/lib/shopify_api/resources/customer.rb +4 -1
- data/lib/shopify_api/resources/fulfillment_service.rb +4 -0
- data/lib/shopify_api/resources/order_risk.rb +8 -0
- data/lib/shopify_api/session.rb +18 -18
- data/lib/shopify_api/version.rb +1 -1
- data/test/active_resource/json_errors_test.rb +22 -0
- data/test/article_test.rb +11 -0
- data/test/asset_test.rb +0 -1
- data/test/base_test.rb +0 -7
- data/test/customer_test.rb +10 -0
- data/test/fixtures/customers_search.json +60 -0
- data/test/fixtures/fulfillment_service.json +10 -0
- data/test/fixtures/image.json +10 -0
- data/test/fixtures/images.json +20 -0
- data/test/fixtures/order_risk.json +14 -0
- data/test/fixtures/order_risks.json +28 -0
- data/test/fixtures/recurring_application_charges.json +10 -0
- data/test/fixtures/variant.json +2 -1
- data/test/fixtures/variants.json +8 -4
- data/test/fulfillment_service_test.rb +17 -0
- data/test/image_test.rb +26 -0
- data/test/limits_test.rb +0 -1
- data/test/order_risk_test.rb +46 -0
- data/test/recurring_application_charge_test.rb +21 -0
- data/test/session_test.rb +44 -17
- data/test/test_helper.rb +6 -6
- data/test/variant_test.rb +14 -0
- metadata +49 -18
- checksums.yaml +0 -7
- data/lib/shopify_api/resources/product_search_engine.rb +0 -4
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
rvm:
|
4
|
+
- 2.0.0
|
5
|
+
- 1.9.3
|
6
|
+
|
7
|
+
gemfile:
|
8
|
+
- Gemfile
|
9
|
+
- Gemfile_ar30
|
10
|
+
- Gemfile_ar31
|
11
|
+
- Gemfile_ar32
|
12
|
+
|
13
|
+
install: bundle install
|
14
|
+
|
15
|
+
before_script: echo $OLD_RAKE
|
16
|
+
|
17
|
+
matrix:
|
18
|
+
include:
|
19
|
+
- rvm: 1.9.2
|
20
|
+
gemfile: Gemfile_ar30
|
21
|
+
env: OLD_RAKE=1
|
22
|
+
- rvm: 1.9.2
|
23
|
+
gemfile: Gemfile_ar31
|
24
|
+
env: OLD_RAKE=1
|
25
|
+
- rvm: 1.9.2
|
26
|
+
gemfile: Gemfile_ar32
|
27
|
+
env: OLD_RAKE=1
|
28
|
+
|
29
|
+
|
30
|
+
notifications:
|
31
|
+
flowdock:
|
32
|
+
secure: "RCgSxzMScnqK6bOwkv9sWSdieLBeJla8NcDtM/QmuFW8soTgV6qCTAPAGd4lpjg4vGTaM3DsdHU5GMDbgdWN5dE2Rf09ayFqiZg8OloPMQ63KIwLJyVcw3cVJO5i7smjIpsSjPjBkvAXHIOFcKdsnuYGS4YD8hjl+QrZ3ghi440="
|
data/CHANGELOG
CHANGED
@@ -1,6 +1,18 @@
|
|
1
|
+
== Version 3.2.0
|
2
|
+
|
3
|
+
* in Session::request_token params is no longer optional, you must pass all the params and the method will now extract the code
|
4
|
+
* Fixed JSON errors handling (#103)
|
5
|
+
* Fixed compatibility with Ruby 2.1.x (#83)
|
6
|
+
* Fixed getting parent ID from nested resources like Variants (#44)
|
7
|
+
* Cleaned up compatibility with ActiveResource 4.0.x
|
8
|
+
* Added OrderRisk resource
|
9
|
+
* Added FulfillmentService resource
|
10
|
+
* Removed discontinued ProductSearchEngine resource
|
11
|
+
* Added convenience method Customer#search (#45)
|
12
|
+
|
1
13
|
== Version 3.1.8
|
2
14
|
|
3
|
-
* Expose `index` and `show` actions of `Location`
|
15
|
+
* Expose `index` and `show` actions of `Location`
|
4
16
|
* Added create_permission_url and request_token helper methods
|
5
17
|
* Edited the readme to better describe the getting started procedure
|
6
18
|
|
@@ -114,7 +126,7 @@ requests/responses
|
|
114
126
|
|
115
127
|
== Version 1.1.1 (October 5, 2010)
|
116
128
|
|
117
|
-
* Remove hard coded xml formatting in API calls
|
129
|
+
* Remove hard coded xml formatting in API calls
|
118
130
|
* Remove jeweler stuff
|
119
131
|
* Ruby 1.9 encoding fix
|
120
132
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
shopify_api (3.
|
4
|
+
shopify_api (3.2.0)
|
5
5
|
activeresource (>= 3.0.0)
|
6
6
|
thor (>= 0.14.4)
|
7
7
|
|
@@ -24,7 +24,7 @@ GEM
|
|
24
24
|
atomic (1.1.14)
|
25
25
|
builder (3.1.4)
|
26
26
|
fakeweb (1.3.0)
|
27
|
-
i18n (0.6.
|
27
|
+
i18n (0.6.9)
|
28
28
|
metaclass (0.0.1)
|
29
29
|
minitest (4.7.5)
|
30
30
|
mocha (0.14.0)
|
data/Gemfile_ar30
ADDED
data/Gemfile_ar31
ADDED
data/Gemfile_ar32
ADDED
data/README.rdoc
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
{<img src="https://travis-ci.org/Shopify/shopify_api.png?branch=master" alt="Build Status" />}[https://travis-ci.org/Shopify/shopify_api]
|
1
2
|
= Shopify API
|
2
3
|
|
3
4
|
The Shopify API gem allows Ruby developers to programmatically access the admin section of Shopify stores.
|
@@ -12,7 +13,7 @@ The API is implemented as JSON over HTTP using all four verbs (GET/POST/PUT/DELE
|
|
12
13
|
All API usage happens through Shopify applications, created by either shop owners for their own shops, or by Shopify Partners for use by other shop owners:
|
13
14
|
|
14
15
|
* Shop owners can create applications for themselves through their own admin: http://docs.shopify.com/api/tutorials/creating-a-private-app
|
15
|
-
* Shopify Partners create applications through their admin: http://app.shopify.com/services/partners
|
16
|
+
* Shopify Partners create applications through their admin: http://app.shopify.com/services/partners
|
16
17
|
|
17
18
|
For more information and detailed documentation about the API visit http://api.shopify.com
|
18
19
|
|
@@ -31,11 +32,11 @@ ShopifyAPI uses ActiveResource to communicate with the REST web service. ActiveR
|
|
31
32
|
1. First create a new application in either the partners admin or your store admin. For a private App you'll need the API_KEY and the PASSWORD otherwise you'll need the API_KEY and SHARED_SECRET.
|
32
33
|
|
33
34
|
2. For a private App you just need to set the base site url as follows:
|
34
|
-
|
35
|
+
|
35
36
|
shop_url = "https://#{API_KEY}:#{PASSWORD}@SHOP_NAME.myshopify.com/admin"
|
36
37
|
ShopifyAPI::Base.site = shop_url
|
37
38
|
|
38
|
-
That's it you're done, skip to step 7 and start using the API!
|
39
|
+
That's it, you're done, skip to step 7 and start using the API!
|
39
40
|
|
40
41
|
For a partner app you will need to supply two parameters to the Session class before you instantiate it:
|
41
42
|
|
@@ -52,15 +53,15 @@ ShopifyAPI uses ActiveResource to communicate with the REST web service. ActiveR
|
|
52
53
|
* redirect_uri – Optional – The URL that the merchant will be sent to once authentication is complete. Defaults to the URL specified in the application settings and must be the same host as that URL.
|
53
54
|
|
54
55
|
We've added the create_permision_url method to make this easier, first instantiate your session object:
|
55
|
-
|
56
|
+
|
56
57
|
session = ShopifyAPI::Session.new("SHOP_NAME.myshopify.com")
|
57
58
|
|
58
|
-
|
59
|
+
Then call:
|
59
60
|
|
60
61
|
scope = ["write_products"]
|
61
62
|
permission_url = session.create_permission_url(scope)
|
62
63
|
|
63
|
-
|
64
|
+
or if you want a custom redirect_uri:
|
64
65
|
|
65
66
|
permission_url = session.create_permission_url(scope, "https://my_redirect_uri.com")
|
66
67
|
|
@@ -69,18 +70,20 @@ ShopifyAPI uses ActiveResource to communicate with the REST web service. ActiveR
|
|
69
70
|
POST https://SHOP_NAME.myshopify.com/admin/oauth/access_token
|
70
71
|
|
71
72
|
with the following parameters:
|
72
|
-
|
73
|
+
|
73
74
|
* client_id – Required – The API key for your app
|
74
75
|
* client_secret – Required – The shared secret for your app
|
75
76
|
* code – Required – The token you received in step 3
|
76
77
|
|
77
78
|
and you'll get your permanent access token back in the response.
|
78
79
|
|
79
|
-
There is a method to make the request and get the token for you
|
80
|
+
There is a method to make the request and get the token for you. Pass
|
81
|
+
all the params received from the previous call and the method will verify
|
82
|
+
the params, extract the temp code and then request your token:
|
80
83
|
|
81
|
-
token = session.request_token(
|
84
|
+
token = session.request_token(params)
|
82
85
|
|
83
|
-
|
86
|
+
This method will save the token to the session object and return it. For future sessions simply pass the token in when creating the session object:
|
84
87
|
|
85
88
|
session = ShopifyAPI::Session.new("SHOP_NAME.myshopify.com", token)
|
86
89
|
|
@@ -110,18 +113,18 @@ ShopifyAPI uses ActiveResource to communicate with the REST web service. ActiveR
|
|
110
113
|
|
111
114
|
products = ShopifyAPI::Session.temp("SHOP_NAME.myshopify.com", token) { ShopifyAPI::Product.find(:all) }
|
112
115
|
|
113
|
-
8. If you want to work with another shop, you'll first need to clear the session
|
116
|
+
8. If you want to work with another shop, you'll first need to clear the session:
|
114
117
|
|
115
118
|
ShopifyAPI::Base.clear_session
|
116
119
|
|
117
120
|
|
118
121
|
=== Console
|
119
122
|
|
120
|
-
This package also includes the
|
123
|
+
This package also includes the +shopify+ executable to make it easy to open up an interactive console to use the API with a shop.
|
121
124
|
|
122
125
|
1. Obtain a private API key and password to use with your shop (step 2 in "Getting Started")
|
123
126
|
|
124
|
-
2. Use the
|
127
|
+
2. Use the +shopify+ script to save the credentials for the shop to quickly log in.
|
125
128
|
|
126
129
|
shopify add yourshopname
|
127
130
|
|
@@ -139,12 +142,12 @@ This package also includes the `shopify` executable to make it easy to open up a
|
|
139
142
|
== Using Development Version
|
140
143
|
|
141
144
|
Download the source code and run:
|
142
|
-
|
145
|
+
|
143
146
|
rake install
|
144
147
|
|
145
148
|
== Additional Resources
|
146
149
|
|
147
|
-
http://
|
150
|
+
http://docs.shopify.com/api <= Read the tech docs!
|
148
151
|
|
149
152
|
http://ecommerce.shopify.com/c/shopify-apis-and-technology <= Ask questions on the forums!
|
150
153
|
|
@@ -1,22 +1,21 @@
|
|
1
1
|
module ActiveResource
|
2
2
|
class Base
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
if ActiveResource::VERSION::MAJOR < 4
|
4
|
+
# Backported from ActiveResource master branch
|
5
|
+
def self.headers
|
6
|
+
@headers ||= {}
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
if superclass != Object && superclass.headers
|
9
|
+
@headers = superclass.headers.merge(@headers)
|
10
|
+
else
|
11
|
+
@headers
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# https://github.com/rails/activeresource/commit/dfef85ce8f653f75673631b2950fcdb0781c313c
|
16
|
+
def self.delete(id, options = {})
|
17
|
+
connection.delete(element_path(id, options), headers)
|
11
18
|
end
|
12
|
-
end
|
13
|
-
# https://github.com/rails/activeresource/commit/dfef85ce8f653f75673631b2950fcdb0781c313c
|
14
|
-
def self.delete(id, options = {})
|
15
|
-
connection.delete(element_path(id, options), headers)
|
16
|
-
end
|
17
|
-
def self.build(attributes = {})
|
18
|
-
attrs = self.format.decode(connection.get("#{new_element_path}", headers).body).merge(attributes)
|
19
|
-
self.new(attrs)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -17,6 +17,20 @@ module DisablePrefixCheck
|
|
17
17
|
|
18
18
|
options[resource_id].nil? ? "/admin/" : "/admin/#{resource_type}/#{options[resource_id]}/"
|
19
19
|
end
|
20
|
+
|
21
|
+
define_singleton_method :instantiate_record do |record, prefix_options = {}|
|
22
|
+
new_record(record).tap do |resource|
|
23
|
+
resource.prefix_options = prefix_options unless prefix_options.blank?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def new_record(record)
|
29
|
+
if ActiveSupport::VERSION::MAJOR == 3 && ActiveSupport::VERSION::MINOR == 0
|
30
|
+
new(record)
|
31
|
+
else
|
32
|
+
new(record, true)
|
33
|
+
end
|
20
34
|
end
|
21
35
|
end
|
22
36
|
end
|
@@ -2,6 +2,16 @@ require 'active_resource/base'
|
|
2
2
|
|
3
3
|
module ActiveResource
|
4
4
|
class Errors < ActiveModel::Errors
|
5
|
+
def from_json(json, save_cache = false)
|
6
|
+
data = ActiveSupport::JSON.decode(json)['errors'] || {} rescue {}
|
7
|
+
case data
|
8
|
+
when String
|
9
|
+
from_string(data, save_cache)
|
10
|
+
else
|
11
|
+
from_hash(data, save_cache)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
5
15
|
def from_hash(messages, save_cache = false)
|
6
16
|
clear unless save_cache
|
7
17
|
|
@@ -12,10 +22,10 @@ module ActiveResource
|
|
12
22
|
end
|
13
23
|
end
|
14
24
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
def from_string(error, save_cache = false)
|
26
|
+
clear unless save_cache
|
27
|
+
|
28
|
+
add("message", error)
|
19
29
|
end
|
20
30
|
end
|
21
31
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# ActiveSupport 3.0 doesn't URL-encode paths with arrays as params properly.
|
2
|
+
# Backported from ActiveSupport > 3.0
|
3
|
+
if ActiveSupport::VERSION::MAJOR == 3 && ActiveSupport::VERSION::MINOR == 0
|
4
|
+
class Object
|
5
|
+
def to_query(key)
|
6
|
+
require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
|
7
|
+
"#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/shopify_api.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'shopify_api/resources/base'
|
2
|
-
Dir.glob
|
2
|
+
Dir.glob("#{File.dirname(__FILE__)}/resources/*").each { |file| require(file) }
|
@@ -3,8 +3,11 @@ module ShopifyAPI
|
|
3
3
|
include Metafields
|
4
4
|
|
5
5
|
def orders
|
6
|
-
Order.find(:all, :
|
6
|
+
Order.find(:all, params: {customer_id: self.id})
|
7
7
|
end
|
8
8
|
|
9
|
+
def self.search(params)
|
10
|
+
find(:all, from: :search, params: params)
|
11
|
+
end
|
9
12
|
end
|
10
13
|
end
|
data/lib/shopify_api/session.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
|
2
2
|
module ShopifyAPI
|
3
|
-
|
3
|
+
|
4
4
|
class Session
|
5
5
|
cattr_accessor :api_key
|
6
6
|
cattr_accessor :secret
|
7
|
-
cattr_accessor :protocol
|
7
|
+
cattr_accessor :protocol
|
8
8
|
self.protocol = 'https'
|
9
9
|
|
10
10
|
attr_accessor :url, :token, :name
|
11
|
-
|
11
|
+
|
12
12
|
class << self
|
13
|
-
|
13
|
+
|
14
14
|
def setup(params)
|
15
15
|
params.each { |k,value| send("#{k}=", value) }
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def temp(domain, token, &block)
|
19
19
|
session = new(domain, token)
|
20
20
|
begin
|
@@ -31,7 +31,7 @@ module ShopifyAPI
|
|
31
31
|
ShopifyAPI::Base.activate_session(original_session)
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def prepare_url(url)
|
36
36
|
return nil if url.blank?
|
37
37
|
url.gsub!(/https?:\/\//, '') # remove http:// or https://
|
@@ -57,16 +57,10 @@ module ShopifyAPI
|
|
57
57
|
end
|
58
58
|
|
59
59
|
end
|
60
|
-
|
61
|
-
def initialize(url, token = nil
|
60
|
+
|
61
|
+
def initialize(url, token = nil)
|
62
62
|
self.url, self.token = url, token
|
63
63
|
self.class.prepare_url(self.url)
|
64
|
-
|
65
|
-
if params
|
66
|
-
unless self.class.validate_signature(params) && params[:timestamp].to_i > 24.hours.ago.utc.to_i
|
67
|
-
raise "Invalid Signature: Possible malicious login"
|
68
|
-
end
|
69
|
-
end
|
70
64
|
end
|
71
65
|
|
72
66
|
def create_permission_url(scope, redirect_uri = nil)
|
@@ -75,9 +69,15 @@ module ShopifyAPI
|
|
75
69
|
"#{protocol}://#{url}/admin/oauth/authorize?#{parameterize(params)}"
|
76
70
|
end
|
77
71
|
|
78
|
-
def request_token(
|
72
|
+
def request_token(params)
|
79
73
|
return token if token
|
80
|
-
|
74
|
+
|
75
|
+
unless self.class.validate_signature(params) && params[:timestamp].to_i > 24.hours.ago.utc.to_i
|
76
|
+
raise "Invalid Signature: Possible malicious login"
|
77
|
+
end
|
78
|
+
|
79
|
+
code = params['code']
|
80
|
+
|
81
81
|
response = access_token_request(code)
|
82
82
|
|
83
83
|
if response.code == "200"
|
@@ -98,14 +98,14 @@ module ShopifyAPI
|
|
98
98
|
def valid?
|
99
99
|
url.present? && token.present?
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
private
|
103
103
|
def parameterize(params)
|
104
104
|
URI.escape(params.collect{|k,v| "#{k}=#{v}"}.join('&'))
|
105
105
|
end
|
106
106
|
|
107
107
|
def access_token_request(code)
|
108
|
-
uri = URI.parse("#{protocol}://#{url}/admin/oauth/access_token")
|
108
|
+
uri = URI.parse("#{protocol}://#{url}/admin/oauth/access_token")
|
109
109
|
https = Net::HTTP.new(uri.host, uri.port)
|
110
110
|
https.use_ssl = true
|
111
111
|
request = Net::HTTP::Post.new(uri.request_uri)
|