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.
Files changed (45) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +32 -0
  3. data/CHANGELOG +14 -2
  4. data/Gemfile.lock +2 -2
  5. data/Gemfile_ar30 +9 -0
  6. data/Gemfile_ar31 +9 -0
  7. data/Gemfile_ar32 +9 -0
  8. data/README.rdoc +18 -15
  9. data/lib/active_resource/base_ext.rb +14 -15
  10. data/lib/active_resource/disable_prefix_check.rb +14 -0
  11. data/lib/active_resource/json_errors.rb +14 -4
  12. data/lib/active_resource/to_query.rb +10 -0
  13. data/lib/shopify_api.rb +1 -0
  14. data/lib/shopify_api/resources.rb +1 -1
  15. data/lib/shopify_api/resources/base.rb +4 -0
  16. data/lib/shopify_api/resources/customer.rb +4 -1
  17. data/lib/shopify_api/resources/fulfillment_service.rb +4 -0
  18. data/lib/shopify_api/resources/order_risk.rb +8 -0
  19. data/lib/shopify_api/session.rb +18 -18
  20. data/lib/shopify_api/version.rb +1 -1
  21. data/test/active_resource/json_errors_test.rb +22 -0
  22. data/test/article_test.rb +11 -0
  23. data/test/asset_test.rb +0 -1
  24. data/test/base_test.rb +0 -7
  25. data/test/customer_test.rb +10 -0
  26. data/test/fixtures/customers_search.json +60 -0
  27. data/test/fixtures/fulfillment_service.json +10 -0
  28. data/test/fixtures/image.json +10 -0
  29. data/test/fixtures/images.json +20 -0
  30. data/test/fixtures/order_risk.json +14 -0
  31. data/test/fixtures/order_risks.json +28 -0
  32. data/test/fixtures/recurring_application_charges.json +10 -0
  33. data/test/fixtures/variant.json +2 -1
  34. data/test/fixtures/variants.json +8 -4
  35. data/test/fulfillment_service_test.rb +17 -0
  36. data/test/image_test.rb +26 -0
  37. data/test/limits_test.rb +0 -1
  38. data/test/order_risk_test.rb +46 -0
  39. data/test/recurring_application_charge_test.rb +21 -0
  40. data/test/session_test.rb +44 -17
  41. data/test/test_helper.rb +6 -6
  42. data/test/variant_test.rb +14 -0
  43. metadata +49 -18
  44. checksums.yaml +0 -7
  45. data/lib/shopify_api/resources/product_search_engine.rb +0 -4
data/.gitignore CHANGED
@@ -4,3 +4,4 @@ coverage
4
4
  rdoc
5
5
  doc
6
6
  pkg
7
+ .ruby-version
@@ -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
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify_api (3.1.8)
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.5)
27
+ i18n (0.6.9)
28
28
  metaclass (0.0.1)
29
29
  minitest (4.7.5)
30
30
  mocha (0.14.0)
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "activeresource", "~> 3.0.0"
6
+
7
+ if ENV['OLD_RAKE'] == '1'
8
+ gem "rake", "~> 0.9.2"
9
+ end
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "activeresource", "~> 3.1.0"
6
+
7
+ if ENV['OLD_RAKE'] == '1'
8
+ gem "rake", "~> 0.9.2"
9
+ end
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "activeresource", "~> 3.2.0"
6
+
7
+ if ENV['OLD_RAKE'] == '1'
8
+ gem "rake", "~> 0.9.2"
9
+ end
@@ -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
- Then call:
59
+ Then call:
59
60
 
60
61
  scope = ["write_products"]
61
62
  permission_url = session.create_permission_url(scope)
62
63
 
63
- or if you want a custom redirect_uri:
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(code)
84
+ token = session.request_token(params)
82
85
 
83
- Which will request the token, save it to the session object and return it. For future sessions simply pass the token in when creating the session object:
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 `shopify` executable to make it easy to open up an interactive console to use the API with a shop.
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 `shopify` script to save the credentials for the shop to quickly log in.
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://api.shopify.com <= Read the tech docs!
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
- # Backported from ActiveResource master branch
4
- def self.headers
5
- @headers ||= {}
3
+ if ActiveResource::VERSION::MAJOR < 4
4
+ # Backported from ActiveResource master branch
5
+ def self.headers
6
+ @headers ||= {}
6
7
 
7
- if superclass != Object && superclass.headers
8
- @headers = superclass.headers.merge(@headers)
9
- else
10
- @headers
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
- # Grabs errors from a json response.
16
- def from_json(json, save_cache = false)
17
- hash = ActiveSupport::JSON.decode(json)['errors'] || {} rescue {}
18
- from_hash hash, save_cache
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
@@ -11,6 +11,7 @@ require 'shopify_api/json_format'
11
11
  require 'active_resource/json_errors'
12
12
  require 'active_resource/disable_prefix_check'
13
13
  require 'active_resource/base_ext'
14
+ require 'active_resource/to_query'
14
15
 
15
16
  module ShopifyAPI
16
17
  include Limits
@@ -1,2 +1,2 @@
1
1
  require 'shopify_api/resources/base'
2
- Dir.glob "#{File.dirname(__FILE__)}/resources/*", &method(:require)
2
+ Dir.glob("#{File.dirname(__FILE__)}/resources/*").each { |file| require(file) }
@@ -52,6 +52,10 @@ module ShopifyAPI
52
52
 
53
53
  def init_prefix_explicit(resource_type, resource_id)
54
54
  self.prefix = "/admin/#{resource_type}/:#{resource_id}/"
55
+
56
+ define_method resource_id.to_sym do
57
+ @prefix_options[resource_id]
58
+ end
55
59
  end
56
60
  end
57
61
 
@@ -3,8 +3,11 @@ module ShopifyAPI
3
3
  include Metafields
4
4
 
5
5
  def orders
6
- Order.find(:all, :params => {:customer_id => self.id})
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
@@ -0,0 +1,4 @@
1
+ module ShopifyAPI
2
+ class FulfillmentService < Base
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module ShopifyAPI
2
+ class OrderRisk < Base
3
+ init_prefix :order
4
+
5
+ self.collection_name = "risks"
6
+ self.element_name = "risk"
7
+ end
8
+ end
@@ -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, params = 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(code)
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)