spiffy_stores_api 4.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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