spree-api-client 0.0.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/LICENSE.txt +674 -0
  4. data/README.md +31 -38
  5. data/lib/spree_client.rb +3 -0
  6. data/lib/spree_client.rb~ +71 -0
  7. data/lib/spree_client/api.rb +1 -0
  8. data/lib/spree_client/api/v1.rb +53 -0
  9. data/lib/spree_client/api/v1/products.rb +23 -0
  10. data/lib/spree_client/api/v1/properties.rb +12 -0
  11. data/lib/spree_client/api/v1/resources.rb +142 -0
  12. data/lib/spree_client/api/v1/stock_items.rb +27 -0
  13. data/lib/spree_client/api/v1/stock_locations.rb +33 -0
  14. data/lib/spree_client/api/v1/stock_movements.rb +16 -0
  15. data/lib/spree_client/api/v1/taxonomies.rb +12 -0
  16. data/lib/spree_client/api/v1/variants.rb +13 -0
  17. data/lib/spree_client/attributes.rb +27 -0
  18. data/lib/spree_client/models.rb +5 -0
  19. data/lib/spree_client/models/product.rb +7 -0
  20. data/lib/spree_client/models/property.rb +6 -0
  21. data/lib/spree_client/models/stock_item.rb +7 -0
  22. data/lib/spree_client/models/stock_location.rb +7 -0
  23. data/lib/spree_client/models/stock_movement.rb +7 -0
  24. data/lib/spree_client/models/store.rb +7 -0
  25. data/lib/spree_client/models/taxonomy.rb +5 -0
  26. data/lib/spree_client/models/variant.rb +7 -0
  27. metadata +79 -118
  28. data/.gitignore +0 -17
  29. data/.travis.yml +0 -9
  30. data/CONTRIBUTING.md +0 -8
  31. data/Gemfile +0 -3
  32. data/LICENSE +0 -22
  33. data/Rakefile +0 -7
  34. data/lib/spree-api-client.rb +0 -49
  35. data/lib/spree-api-client/addresses.rb +0 -15
  36. data/lib/spree-api-client/connection.rb +0 -30
  37. data/lib/spree-api-client/countries.rb +0 -15
  38. data/lib/spree-api-client/line_items.rb +0 -19
  39. data/lib/spree-api-client/orders.rb +0 -31
  40. data/lib/spree-api-client/payments.rb +0 -43
  41. data/lib/spree-api-client/products.rb +0 -31
  42. data/lib/spree-api-client/properties.rb +0 -31
  43. data/lib/spree-api-client/request.rb +0 -49
  44. data/lib/spree-api-client/return_authorizations.rb +0 -31
  45. data/lib/spree-api-client/shipments.rb +0 -15
  46. data/lib/spree-api-client/taxonomies.rb +0 -31
  47. data/lib/spree-api-client/taxons.rb +0 -27
  48. data/lib/spree-api-client/variants.rb +0 -31
  49. data/lib/spree-api-client/version.rb +0 -7
  50. data/lib/spree-api-client/zones.rb +0 -31
  51. data/spec/addresses_spec.rb +0 -11
  52. data/spec/client_spec.rb +0 -31
  53. data/spec/countries_spec.rb +0 -11
  54. data/spec/orders_spec.rb +0 -11
  55. data/spec/payments_spec.rb +0 -11
  56. data/spec/products_spec.rb +0 -11
  57. data/spec/properties_spec.rb +0 -11
  58. data/spec/return_authorizations_spec.rb +0 -11
  59. data/spec/shipments_spec.rb +0 -11
  60. data/spec/spec_helper.rb +0 -5
  61. data/spec/taxonomies_spec.rb +0 -11
  62. data/spec/taxons_spec.rb +0 -11
  63. data/spec/variants_spec.rb +0 -11
  64. data/spec/zones_spec.rb +0 -11
  65. data/spree-api-client.gemspec +0 -27
data/README.md CHANGED
@@ -1,18 +1,12 @@
1
- # Spree::API::Client
2
-
3
- [![Build Status](https://secure.travis-ci.org/andrew/spree-api-client.png)](https://travis-ci.org/andrew/spree-api-client)
4
-
5
- ** Beware: very alpha and untested **
6
-
7
- A rubygem for interacting with the Spree API: http://api.spreecommerce.com/v1/
8
-
9
- Heavily inspired by the excellent Octokit: https://github.com/pengwynn/octokit
1
+ # Spree Ecommerce API client
10
2
 
11
3
  ## Installation
12
4
 
13
- Add this line to your application's Gemfile:
5
+ Add this line to your site's Gemfile:
14
6
 
15
- gem 'spree-api-client'
7
+ ```ruby
8
+ gem 'spree_client'
9
+ ```
16
10
 
17
11
  And then execute:
18
12
 
@@ -20,42 +14,41 @@ And then execute:
20
14
 
21
15
  Or install it yourself as:
22
16
 
23
- $ gem install spree-api-client
17
+ $ gem install spree_client
24
18
 
25
19
  ## Usage
26
20
 
27
- client = Spree::API::Client.new('http://example/api', 'yourapitokenstring')
28
- products = client.products
21
+ Get an API key for your user in `/admin/users`.
22
+
23
+ ```ruby
24
+ spree = SpreeClient::Api::V1.new api_key: 'api key', spree_url: 'http://localhost:3000', store: 'https://my.store'
25
+
26
+ spree.products.index
27
+ => true
29
28
 
30
- ## TODO
29
+ # The results are in the response
30
+ spree.products.response
31
+ => []
32
+ ```
31
33
 
32
- * More tests
33
- * Mock web requests in tests
34
- * documentation
35
- * rdoc generation
36
- * release to rubygems.org
37
- * gemnasium
38
- * code climate
39
- * Error handling
40
- * Autopagination?
34
+ [Read the documentation](https://rubydoc.info/gems/spree_client)
41
35
 
42
- ## Development
43
36
 
44
- Source hosted at [GitHub](http://github.com/andrew/spree-api-client).
45
- Report Issues/Feature requests on [GitHub Issues](http://github.com/andrew/spree-api-client/issues).
37
+ ## Contributing
46
38
 
47
- Tests can be ran with `rake spec`
39
+ Bug reports and pull requests are welcome on 0xacab.org at
40
+ <https://0xacab.org/sutty/spree_client>. This project is
41
+ intended to be a safe, welcoming space for collaboration, and
42
+ contributors are expected to adhere to the [Sutty code of
43
+ conduct](https://sutty.nl/en/code-of-conduct/).
48
44
 
49
- ### Note on Patches/Pull Requests
45
+ ## License
50
46
 
51
- * Fork the project.
52
- * Make your feature addition or bug fix.
53
- * Add tests for it. This is important so I don't break it in a
54
- future version unintentionally.
55
- * Commit, do not mess with rakefile, version, or history.
56
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
57
- * Send me a pull request. Bonus points for topic branches.
47
+ The gem is available as free software under the terms of the GPL3
48
+ License.
58
49
 
59
- ## Copyright
50
+ ## Code of Conduct
60
51
 
61
- Copyright (c) 2012 Andrew Nesbitt. See [LICENSE](https://github.com/andrew/spree-api-client/blob/master/LICENSE) for details.
52
+ Everyone interacting in the `spree_client` project’s codebases, issue
53
+ trackers, chat rooms and mailing lists is expected to follow the [code
54
+ of conduct](https://sutty.nl/en/code-of-conduct/).
@@ -0,0 +1,3 @@
1
+ require_relative 'spree_client/attributes'
2
+ require_relative 'spree_client/models'
3
+ require_relative 'spree_client/api/v1'
@@ -0,0 +1,71 @@
1
+ require 'httparty'
2
+
3
+ require_relative 'spree_client/models'
4
+ require_relative 'spree_client/api/v1'
5
+
6
+ # This class is a client for Spree Commerce Backend. It can push
7
+ # information to it and also retrieve it from the APIs.
8
+ #
9
+ # The Spree Backend needs to have Devise configured with
10
+ # http_authenticatable = true so it can send the credentials as basic
11
+ # authorization header.
12
+ module SpreeClient
13
+ include HTTParty
14
+
15
+ # The backend will redirect in certain actions, we want to be able to
16
+ # distinguish them.
17
+ follow_redirects false
18
+
19
+ # Cookies
20
+ # @return [String]
21
+ attr_accessor :cookies
22
+
23
+ # Initialize an SpreeClient. If not parameters are given it'll try to
24
+ # login to the default development Spree.
25
+ #
26
+ # @param [String] :spree_url The Spree site
27
+ # @param [String] :username Username
28
+ # @param [String] :password Password
29
+ def initialize(spree_url: 'http://localhost:3000', username: 'spree@example.com', password: 'spree123')
30
+ self.class.basic_auth username, password
31
+ self.class.default_options[:base_uri] = HTTParty.normalize_base_uri(spree_url)
32
+ end
33
+
34
+ # Gets an authenticity token from the API by sending credentials to a
35
+ # custom API endpoint. Otherwise we have to download and parse the
36
+ # forms. It stores the cookie so the token can be verified afterwards.
37
+ #
38
+ # @see SpreeClient#cookies
39
+ # @return [String]
40
+ def authenticity_token
41
+ response = self.class.get('/admin/authenticity_token',
42
+ headers: headers)
43
+
44
+ @cookies = response.headers['set-cookie']
45
+
46
+ response.to_s
47
+ end
48
+
49
+ # Taxonomies
50
+ #
51
+ # @see SpreeClient::Taxonomies
52
+ # @return [SpreeClient::Taxonomies]
53
+ def taxonomies
54
+ @taxonomies ||= Taxonomies.new spree: self
55
+ end
56
+
57
+ # Properties
58
+ #
59
+ # @see SpreeClient::Properties
60
+ # @return [SpreeClient::Properties]
61
+ def properties
62
+ @properties ||= Properties.new spree: self
63
+ end
64
+
65
+ # Default headers. If there're cookies it sends them.
66
+ #
67
+ # @return [Hash] Headers
68
+ def headers(extra = {})
69
+ extra.merge({ 'Cookie' => cookies })
70
+ end
71
+ end
@@ -0,0 +1 @@
1
+ require_relative 'api/v1'
@@ -0,0 +1,53 @@
1
+ require 'httparty'
2
+ require_relative 'v1/resources'
3
+ require_relative 'v1/products'
4
+ require_relative 'v1/variants'
5
+ require_relative 'v1/stock_locations'
6
+ require_relative 'v1/stock_items'
7
+ require_relative 'v1/stock_movements'
8
+
9
+ module SpreeClient
10
+ module API
11
+ class V1
12
+ include ::HTTParty
13
+
14
+ attr_reader :api_key, :store
15
+
16
+ def initialize(api_key:, spree_url: 'http://localhost:3000', store: nil)
17
+ @api_key = api_key
18
+ @store = HTTParty.normalize_base_uri(store) if store
19
+ self.class.default_options[:base_uri] = HTTParty.normalize_base_uri(spree_url)
20
+ end
21
+
22
+ # TODO: Meta programming
23
+ def products(**args)
24
+ @products ||= {}
25
+ @products[args.hash.to_s] ||= Products.new **{ api: self }.merge(args)
26
+ end
27
+
28
+ def variants(**args)
29
+ @variants ||= {}
30
+ @variants[args.hash.to_s] ||= Variants.new **{ api: self }.merge(args)
31
+ end
32
+
33
+ def stock_locations(**args)
34
+ @stock_locations ||= {}
35
+ @stock_locations[args.hash.to_s] ||= StockLocations.new **{ api: self }.merge(args)
36
+ end
37
+
38
+ def stock_movements(**args)
39
+ @stock_movements ||= {}
40
+ @stock_movements[args.hash.to_s] ||= StockMovements.new **{ api: self }.merge(args)
41
+ end
42
+
43
+ def stock_items(**args)
44
+ @stock_items ||= {}
45
+ @stock_items[args.hash.to_s] ||= StockItems.new **{ api: self }.merge(args)
46
+ end
47
+
48
+ def headers(extra = {})
49
+ extra.merge({ 'Content-Type' => 'application/json', 'X-Spree-Token' => api_key, 'Origin' => store })
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,23 @@
1
+ module SpreeClient
2
+ module API
3
+ class V1
4
+ # Products
5
+ # @see SpreeClient::API:V1::Resource
6
+ class Products < Resources
7
+ ENDPOINT = '/api/v1/products'
8
+ RESOURCE = SpreeClient::Models::Product
9
+ NAME = 'product'
10
+
11
+ # @return [SpreeClient::API::V1::Variants]
12
+ def variants(**args)
13
+ product_id = default_args.dig(:id) || args.dig(:product_id)
14
+
15
+ raise ArgumentError, 'Needs a product ID' unless product_id
16
+
17
+ @variants ||= {}
18
+ @variants[product_id.to_s.to_sym] ||= Variants.new **{ api: api, product_id: product_id }.merge(args)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ class SpreeClient
2
+ module API
3
+ class V1
4
+ # Properties
5
+ # @see SpreeClient::API:V1::Resource
6
+ class Properties < Resources
7
+ ENDPOINT = '/api/v1/properties'
8
+ RESOURCE = Property
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,142 @@
1
+ require 'uri'
2
+
3
+ module SpreeClient
4
+ module API
5
+ class V1
6
+ class Resources
7
+ # Spree API client instance.
8
+ # @return [SpreeClient::API::V1]
9
+ attr_reader :api
10
+ # Every method caches the response so it can be inspected afterwards.
11
+ # @return [HTTParty::Response] The API response
12
+ attr_reader :response
13
+ # @return [Hash]
14
+ attr_reader :default_args
15
+
16
+ # Initialize
17
+ #
18
+ # @param [SpreeClient::API::V1] :api An API client instance
19
+ def initialize(**args)
20
+ @api = args.delete :api
21
+ @default_args = args
22
+ end
23
+
24
+ # Initialize a new resource
25
+ #
26
+ # @param [Hash] Attributes
27
+ # @return [Struct]
28
+ def new(**args)
29
+ resource_class.new **args
30
+ end
31
+
32
+ # Gets all products or filter with params
33
+ #
34
+ # Filters:
35
+ #
36
+ # ids: comma-separated list of IDs
37
+ # q: Ransack search params (mutually exclusive with ids)
38
+ #
39
+ # Pagination:
40
+ #
41
+ # page: page number
42
+ # per_page: results per page
43
+ #
44
+ # @param [Hash] Query params
45
+ def index(**q)
46
+ @response = api.class.get endpoint(q),
47
+ query: q.slice(:ids, :q, :page, :per_page),
48
+ headers: api.headers
49
+
50
+ response.ok?
51
+ end
52
+
53
+ # Get a single product by ID
54
+ def show(resource)
55
+ @response = api.class.get endpoint(resource), headers: api.headers
56
+
57
+ response.ok?
58
+ end
59
+
60
+ # Creates a resource
61
+ #
62
+ # @see SpreeClient::API::V1#headers
63
+ # @param [Struct,Hash] Model instance
64
+ # @return [Boolean]
65
+ def create(resource)
66
+ resource = new **resource unless resource.is_a? resource_class
67
+
68
+ @response = api.class.post endpoint(resource),
69
+ body: params(resource),
70
+ headers: api.headers
71
+
72
+ response.created?
73
+ end
74
+
75
+ # Updates a resource
76
+ #
77
+ # @see SpreeClient::API::V1#headers
78
+ # @param [Struct,Hash]
79
+ # @return [Boolean]
80
+ def update(resource)
81
+ resource = new resource unless resource.is_a? resource_class
82
+
83
+ @response = api.class.patch endpoint(resource),
84
+ body: params(resource),
85
+ headers: api.headers
86
+
87
+ response.ok?
88
+ end
89
+
90
+ # Deletes a resource
91
+ #
92
+ # @see SpreeClient::API::V1#headers
93
+ # @param [Struct,Hash]
94
+ # @return [Boolean]
95
+ def delete(resource)
96
+ @response = spree.class.delete endpoint(resource), headers: api.headers
97
+
98
+ response.no_content?
99
+ end
100
+
101
+ private
102
+
103
+ # Strong parameters
104
+ #
105
+ # @see SpreeClient#authenticity_token
106
+ # @param [Struct,Nil]
107
+ # @return [Hash]
108
+ def params(resource = nil)
109
+ { resource_name => default_args.merge(resource.to_h.compact) }.to_json
110
+ end
111
+
112
+ # Backend endpoint
113
+ #
114
+ # @param [Struct]
115
+ # @return [String]
116
+ def endpoint(resource = {})
117
+ endpoint = self.class::ENDPOINT + (resource.dig(:id) ? '/:id' : '')
118
+
119
+ parameterize_with endpoint, resource
120
+ end
121
+
122
+ # Generates a URL with :parameter replaced with values
123
+ #
124
+ # @param [String]
125
+ # @param [Struct,Hash]
126
+ def parameterize_with(endpoint, resource = {})
127
+ default_args.merge(resource.to_h.compact).inject(endpoint) do |e, pair|
128
+ e.gsub ':' + pair.first.to_s, pair.last.to_s
129
+ end + '.json'
130
+ end
131
+
132
+ def resource_class
133
+ self.class::RESOURCE
134
+ end
135
+
136
+ def resource_name
137
+ self.class::NAME
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,27 @@
1
+ module SpreeClient
2
+ module API
3
+ class V1
4
+ # Stock Movements
5
+ # @see SpreeClient::API:V1::Resources
6
+ class StockItems < Resources
7
+ ENDPOINT = '/api/v1/stock_locations/:stock_location_id/stock_items'
8
+ RESOURCE = SpreeClient::Models::StockItem
9
+ NAME = 'stock_item'
10
+
11
+ def update(_); end
12
+ def destroy(_); end
13
+
14
+ # @return [SpreeClient::API::V1::StockMovements]
15
+ def stock_movements(**args)
16
+ stock_location_id = default_args.dig(:stock_location_id) || args.dig(:stock_location_id)
17
+ stock_item_id = default_args.dig(:id) || args.dig(:stock_item_id)
18
+
19
+ raise ArgumentError, 'Needs a stock location ID' unless stock_location_id
20
+
21
+ @stock_movements ||= {}
22
+ @stock_movements[stock_location_id.to_s.to_sym] ||= StockMovements.new **{ api: api, stock_location_id: stock_location_id, stock_item_id: stock_item_id }.merge(args)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ module SpreeClient
2
+ module API
3
+ class V1
4
+ # Stock Locations
5
+ # @see SpreeClient::API:V1::Resource
6
+ class StockLocations < Resources
7
+ ENDPOINT = '/api/v1/stock_locations'
8
+ RESOURCE = SpreeClient::Models::StockLocation
9
+ NAME = 'stock_location'
10
+
11
+ # @return [SpreeClient::API::V1::StockMovements]
12
+ def stock_movements(**args)
13
+ stock_location_id = default_args.dig(:id) || args.dig(:stock_location_id)
14
+
15
+ raise ArgumentError, 'Needs a stock location ID' unless stock_location_id
16
+
17
+ @stock_movements ||= {}
18
+ @stock_movements[stock_location_id.to_s.to_sym] ||= StockMovements.new **{ api: api, stock_location_id: stock_location_id }.merge(args)
19
+ end
20
+
21
+ # @return [SpreeClient::API::V1::StockItems]
22
+ def stock_items(**args)
23
+ stock_location_id = default_args.dig(:id) || args.dig(:stock_location_id)
24
+
25
+ raise ArgumentError, 'Needs a stock location ID' unless stock_location_id
26
+
27
+ @stock_items ||= {}
28
+ @stock_items[stock_location_id.to_s.to_sym] ||= StockItems.new **{ api: api, stock_location_id: stock_location_id }.merge(args)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end