spiffy_stores_api 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +10 -0
  4. data/.travis.yml +14 -0
  5. data/CHANGELOG +3 -0
  6. data/Gemfile +5 -0
  7. data/Gemfile_ar40 +5 -0
  8. data/Gemfile_ar41 +5 -0
  9. data/Gemfile_ar50 +5 -0
  10. data/Gemfile_ar_master +5 -0
  11. data/README.md +200 -0
  12. data/Rakefile +39 -0
  13. data/lib/active_resource/base_ext.rb +21 -0
  14. data/lib/active_resource/connection_ext.rb +10 -0
  15. data/lib/active_resource/detailed_log_subscriber.rb +19 -0
  16. data/lib/active_resource/disable_prefix_check.rb +36 -0
  17. data/lib/active_resource/json_errors.rb +31 -0
  18. data/lib/active_resource/to_query.rb +10 -0
  19. data/lib/spiffy_stores_api.rb +29 -0
  20. data/lib/spiffy_stores_api/connection.rb +33 -0
  21. data/lib/spiffy_stores_api/countable.rb +14 -0
  22. data/lib/spiffy_stores_api/json_format.rb +18 -0
  23. data/lib/spiffy_stores_api/limits.rb +86 -0
  24. data/lib/spiffy_stores_api/metafields.rb +19 -0
  25. data/lib/spiffy_stores_api/resources.rb +2 -0
  26. data/lib/spiffy_stores_api/resources/address.rb +4 -0
  27. data/lib/spiffy_stores_api/resources/article.rb +20 -0
  28. data/lib/spiffy_stores_api/resources/base.rb +86 -0
  29. data/lib/spiffy_stores_api/resources/blog.rb +9 -0
  30. data/lib/spiffy_stores_api/resources/collect.rb +5 -0
  31. data/lib/spiffy_stores_api/resources/country.rb +4 -0
  32. data/lib/spiffy_stores_api/resources/customer.rb +24 -0
  33. data/lib/spiffy_stores_api/resources/image.rb +16 -0
  34. data/lib/spiffy_stores_api/resources/metafield.rb +12 -0
  35. data/lib/spiffy_stores_api/resources/order.rb +23 -0
  36. data/lib/spiffy_stores_api/resources/page.rb +5 -0
  37. data/lib/spiffy_stores_api/resources/product.rb +32 -0
  38. data/lib/spiffy_stores_api/resources/province.rb +5 -0
  39. data/lib/spiffy_stores_api/resources/script_tag.rb +4 -0
  40. data/lib/spiffy_stores_api/resources/standard_collection.rb +18 -0
  41. data/lib/spiffy_stores_api/resources/store.rb +18 -0
  42. data/lib/spiffy_stores_api/resources/super_collection.rb +14 -0
  43. data/lib/spiffy_stores_api/resources/variant.rb +8 -0
  44. data/lib/spiffy_stores_api/resources/webhook.rb +4 -0
  45. data/lib/spiffy_stores_api/session.rb +145 -0
  46. data/lib/spiffy_stores_api/version.rb +3 -0
  47. data/spiffy_stores_api.gemspec +34 -0
  48. data/test/active_resource/json_errors_test.rb +19 -0
  49. data/test/article_test.rb +73 -0
  50. data/test/base_test.rb +112 -0
  51. data/test/blog_test.rb +8 -0
  52. data/test/collect_test.rb +9 -0
  53. data/test/countable_test.rb +13 -0
  54. data/test/customer_test.rb +50 -0
  55. data/test/fixtures/article.json +15 -0
  56. data/test/fixtures/articles.json +39 -0
  57. data/test/fixtures/asset.json +9 -0
  58. data/test/fixtures/assets.json +136 -0
  59. data/test/fixtures/authors.json +1 -0
  60. data/test/fixtures/blog.json +12 -0
  61. data/test/fixtures/blogs.json +13 -0
  62. data/test/fixtures/collect.json +10 -0
  63. data/test/fixtures/custom_collection.json +17 -0
  64. data/test/fixtures/customers.json +64 -0
  65. data/test/fixtures/customers_search.json +66 -0
  66. data/test/fixtures/image.json +10 -0
  67. data/test/fixtures/images.json +20 -0
  68. data/test/fixtures/metafield.json +13 -0
  69. data/test/fixtures/metafields.json +26 -0
  70. data/test/fixtures/o_auth_revoke.json +5 -0
  71. data/test/fixtures/order.json +297 -0
  72. data/test/fixtures/orders.json +299 -0
  73. data/test/fixtures/product.json +116 -0
  74. data/test/fixtures/redirect.json +7 -0
  75. data/test/fixtures/script_tag.json +10 -0
  76. data/test/fixtures/script_tags.json +18 -0
  77. data/test/fixtures/smart_collection.json +21 -0
  78. data/test/fixtures/store.json +35 -0
  79. data/test/fixtures/tags.json +1 -0
  80. data/test/fixtures/transaction.json +29 -0
  81. data/test/fixtures/variant.json +23 -0
  82. data/test/fixtures/variants.json +88 -0
  83. data/test/fixtures/webhook.json +10 -0
  84. data/test/fixtures/webhooks.json +18 -0
  85. data/test/metafield_test.rb +46 -0
  86. data/test/store_test.rb +58 -0
  87. data/test/test_helper.rb +90 -0
  88. metadata +219 -0
@@ -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
@@ -0,0 +1,29 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'active_resource'
4
+ require 'active_support/core_ext/class/attribute_accessors'
5
+ require 'digest/md5'
6
+ require 'base64'
7
+ require 'active_resource/detailed_log_subscriber'
8
+ require 'spiffy_stores_api/limits'
9
+ require 'spiffy_stores_api/json_format'
10
+ require 'active_resource/json_errors'
11
+ require 'active_resource/disable_prefix_check'
12
+ require 'active_resource/base_ext'
13
+ require 'active_resource/to_query'
14
+
15
+ module SpiffyStoresAPI
16
+ include Limits
17
+ end
18
+
19
+ require 'spiffy_stores_api/metafields'
20
+ require 'spiffy_stores_api/countable'
21
+ require 'spiffy_stores_api/resources'
22
+ require 'spiffy_stores_api/session'
23
+ require 'spiffy_stores_api/connection'
24
+
25
+ if SpiffyStoresAPI::Base.respond_to?(:connection_class)
26
+ SpiffyStoresAPI::Base.connection_class = SpiffyStoresAPI::Connection
27
+ else
28
+ require 'active_resource/connection_ext'
29
+ end
@@ -0,0 +1,33 @@
1
+ module SpiffyStoresAPI
2
+ class Connection < ActiveResource::Connection
3
+ attr_reader :response
4
+
5
+ module ResponseCapture
6
+ def handle_response(response)
7
+ @response = super
8
+ end
9
+ end
10
+
11
+ include ResponseCapture
12
+
13
+ module RequestNotification
14
+ def request(method, path, *arguments)
15
+ super.tap do |response|
16
+ notify_about_request(response, arguments)
17
+ end
18
+ rescue => e
19
+ notify_about_request(e.response, arguments) if e.respond_to?(:response)
20
+ raise
21
+ end
22
+
23
+ def notify_about_request(response, arguments)
24
+ ActiveSupport::Notifications.instrument("request.active_resource_detailed") do |payload|
25
+ payload[:response] = response
26
+ payload[:data] = arguments
27
+ end
28
+ end
29
+ end
30
+
31
+ include RequestNotification
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ module SpiffyStoresAPI
2
+ module Countable
3
+ def count(options = {})
4
+ data = get(:count, options)
5
+
6
+ count = case data
7
+ when Hash then data["count"]
8
+ else data
9
+ end
10
+
11
+ Integer(count)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module ActiveResource
2
+
3
+ # ActiveResource 3.1 removes root on decoding, so this patch is only needed in 3.0
4
+ if ActiveResource::VERSION::MAJOR == 3 && ActiveResource::VERSION::MINOR == 0
5
+ module Formats
6
+ module JsonFormat
7
+ def decode(json)
8
+ data = ActiveSupport::JSON.decode(json)
9
+ if data.is_a?(Hash) && data.keys.size == 1
10
+ data.values.first
11
+ else
12
+ data
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,86 @@
1
+ module SpiffyStoresAPI
2
+ module Limits
3
+ class LimitUnavailable < StandardError; end
4
+
5
+ def self.included(klass)
6
+ klass.send(:extend, ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ # The ratelimit header comes from rack-ratelimit
12
+ # The parameters provided are
13
+ # name
14
+ # period
15
+ # limit
16
+ # remaining
17
+ # until
18
+ # {"name":"API","period":300,"limit":500,"remaining":496,"until":"2014-11-28T03:45:00Z"}
19
+ CREDIT_LIMIT_HEADER_PARAM = {
20
+ :store => 'http_x_ratelimit'
21
+ }
22
+
23
+ ##
24
+ # How many more API calls can I make?
25
+ # @return {Integer}
26
+ #
27
+ def credit_left
28
+ credit_limit(:store) - credit_used(:store)
29
+ end
30
+ alias_method :available_calls, :credit_left
31
+
32
+ ##
33
+ # Have I reached my API call limit?
34
+ # @return {Boolean}
35
+ #
36
+ def credit_maxed?
37
+ credit_left <= 0
38
+ end
39
+ alias_method :maxed?, :credit_maxed?
40
+
41
+ ##
42
+ # How many total API calls can I make?
43
+ # NOTE: subtracting 1 from credit_limit because I think SpiffyStoresAPI cuts off at 299 or store limits.
44
+ # @param {Symbol} scope [:store]
45
+ # @return {Integer}
46
+ #
47
+ def credit_limit(scope=:store)
48
+ @api_credit_limit ||= {}
49
+ @api_credit_limit[scope] ||= api_credit_limit_param(scope).pop.to_i - 1
50
+ end
51
+ alias_method :call_limit, :credit_limit
52
+
53
+ ##
54
+ # How many API calls have I made?
55
+ # @param {Symbol} scope [:store]
56
+ # @return {Integer}
57
+ #
58
+ def credit_used(scope=:store)
59
+ api_credit_limit_param(scope).shift.to_i
60
+ end
61
+ alias_method :call_count, :credit_used
62
+
63
+ ##
64
+ # @return {HTTPResonse}
65
+ #
66
+ def response
67
+ Store.current unless SpiffyStoresAPI::Base.connection.response
68
+ SpiffyStoresAPI::Base.connection.response
69
+ end
70
+
71
+ private
72
+
73
+ ##
74
+ # @return {Array}
75
+ #
76
+ def api_credit_limit_param(scope)
77
+ header = response[CREDIT_LIMIT_HEADER_PARAM[scope]]
78
+ raise LimitUnavailable unless header
79
+ p = JSON.parse(header)
80
+ p_limit = p['limit'].to_i
81
+ p_used = p_limit - p['remaining'].to_i
82
+ [p_used, p_limit]
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,19 @@
1
+ module SpiffyStoresAPI
2
+ module Metafields
3
+ def metafields(**options)
4
+ options.merge!(resource: self.class.collection_name, resource_id: id)
5
+ Metafield.find(:all, params: options)
6
+ end
7
+
8
+ def add_metafield(metafield)
9
+ raise ArgumentError, "You can only add metafields to resource that has been saved" if new?
10
+
11
+ metafield.prefix_options = {
12
+ :resource => self.class.collection_name,
13
+ :resource_id => id
14
+ }
15
+ metafield.save
16
+ metafield
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,2 @@
1
+ require 'spiffy_stores_api/resources/base'
2
+ Dir.glob("#{File.dirname(__FILE__)}/resources/*").each { |file| require(file) }
@@ -0,0 +1,4 @@
1
+ module SpiffyStoresAPI
2
+ class Address < Base
3
+ end
4
+ end
@@ -0,0 +1,20 @@
1
+ module SpiffyStoresAPI
2
+ class Article < Base
3
+ include Metafields
4
+ include DisablePrefixCheck
5
+
6
+ conditional_prefix :blog
7
+
8
+ # def comments
9
+ # Comment.find(:all, :params => { :article_id => id })
10
+ # end
11
+
12
+ def self.authors(options = {})
13
+ get(:authors, options)
14
+ end
15
+
16
+ def self.tags(options={})
17
+ get(:tags, options)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,86 @@
1
+ require 'spiffy_stores_api/version'
2
+
3
+ module SpiffyStoresAPI
4
+ class Base < ActiveResource::Base
5
+ class InvalidSessionError < StandardError; end
6
+ extend Countable
7
+ self.timeout = 90
8
+ self.include_root_in_json = false
9
+ self.headers['User-Agent'] = ["SpiffyStoresAPI/#{SpiffyStoresAPI::VERSION}",
10
+ "ActiveResource/#{ActiveResource::VERSION::STRING}",
11
+ "Ruby/#{RUBY_VERSION}"].join(' ')
12
+
13
+ def encode(options = {})
14
+ same = dup
15
+ same.attributes = {self.class.element_name => same.attributes} if self.class.format.extension == 'json'
16
+
17
+ same.send("to_#{self.class.format.extension}", options)
18
+ end
19
+
20
+ def as_json(options = nil)
21
+ root = options[:root] if options.try(:key?, :root)
22
+ if include_root_in_json
23
+ root = self.class.model_name.element if root == true
24
+ { root => serializable_hash(options) }
25
+ else
26
+ serializable_hash(options)
27
+ end
28
+ end
29
+
30
+ class << self
31
+ if ActiveResource::Base.respond_to?(:_headers) && ActiveResource::Base.respond_to?(:_headers_defined?)
32
+ def headers
33
+ if _headers_defined?
34
+ _headers
35
+ elsif superclass != Object && superclass.headers
36
+ superclass.headers
37
+ else
38
+ _headers ||= {}
39
+ end
40
+ end
41
+ else
42
+ def headers
43
+ if defined?(@headers)
44
+ @headers
45
+ elsif superclass != Object && superclass.headers
46
+ superclass.headers
47
+ else
48
+ @headers ||= {}
49
+ end
50
+ end
51
+ end
52
+
53
+ def activate_session(session)
54
+ raise InvalidSessionError.new("Session cannot be nil") if session.nil?
55
+ self.site = session.site
56
+ self.headers.merge!('Authorization' => "Bearer #{session.token}")
57
+ end
58
+
59
+ def clear_session
60
+ self.site = nil
61
+ self.headers.delete('Authorization')
62
+ end
63
+
64
+ def init_prefix(resource)
65
+ init_prefix_explicit(resource.to_s.pluralize, "#{resource}_id")
66
+ end
67
+
68
+ def init_prefix_explicit(resource_type, resource_id)
69
+ self.prefix = "/api/#{resource_type}/:#{resource_id}/"
70
+
71
+ define_method resource_id.to_sym do
72
+ @prefix_options[resource_id]
73
+ end
74
+ end
75
+ end
76
+
77
+ def persisted?
78
+ !id.nil?
79
+ end
80
+
81
+ private
82
+ def only_id
83
+ encode(:only => :id, :include => [], :methods => [])
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,9 @@
1
+ module SpiffyStoresAPI
2
+ class Blog < Base
3
+ include Metafields
4
+
5
+ def articles
6
+ Article.find(:all, :params => { :blog_id => id })
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module SpiffyStoresAPI
2
+ # For adding/removing products from custom collections
3
+ class Collect < Base
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module SpiffyStoresAPI
2
+ class Country < Base
3
+ end
4
+ end
@@ -0,0 +1,24 @@
1
+ module SpiffyStoresAPI
2
+ class Customer < Base
3
+ include Metafields
4
+
5
+ def orders
6
+ Order.find(:all, params: {customer_id: self.id})
7
+ end
8
+
9
+ def self.search(params)
10
+ find(:all, from: :search, params: params)
11
+ end
12
+
13
+ def account_activation_url
14
+ resource = post(:account_activation_url, {}, only_id)
15
+ data = ActiveSupport::JSON.decode(resource.body.to_s)
16
+ result = nil
17
+
18
+ if data.key?('account_activation_url')
19
+ result = data['account_activation_url']
20
+ end
21
+ result
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ module SpiffyStoresAPI
2
+ class Image < Base
3
+ init_prefix :product
4
+
5
+ # generate a method for each possible image variant
6
+ [:pico, :icon, :thumb, :small, :compact, :medium, :large, :grande, :original].each do |m|
7
+ reg_exp_match = "/\\1_#{m}.\\2"
8
+ define_method(m) { src.gsub(/\/(.*)\.(\w{2,4})/, reg_exp_match) }
9
+ end
10
+
11
+ def attach_image(data, filename = nil)
12
+ attributes['attachment'] = Base64.encode64(data)
13
+ attributes['filename'] = filename unless filename.nil?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module SpiffyStoresAPI
2
+ class Metafield < Base
3
+ include DisablePrefixCheck
4
+
5
+ conditional_prefix :resource, true
6
+
7
+ def value
8
+ return if attributes["value"].nil?
9
+ attributes["value_type"] == "integer" ? attributes["value"].to_i : attributes["value"]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ module SpiffyStoresAPI
2
+ class Order < Base
3
+ include Metafields
4
+
5
+ def close; load_attributes_from_response(post(:close, {}, only_id)); end
6
+ def open; load_attributes_from_response(post(:open, {}, only_id)); end
7
+
8
+ def cancel(options = {})
9
+ load_attributes_from_response(post(:cancel, {}, options.to_json))
10
+ end
11
+
12
+ def transactions
13
+ Transaction.find(:all, :params => { :order_id => id })
14
+ end
15
+
16
+ def capture(amount = "")
17
+ Transaction.create(:amount => amount, :kind => "capture", :order_id => id)
18
+ end
19
+
20
+ class ClientDetails < Base
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module SpiffyStoresAPI
2
+ class Page < Base
3
+ include Metafields
4
+ end
5
+ end