spree_api 3.1.14 → 3.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/app/controllers/spree/api/base_controller.rb +2 -2
  4. data/app/controllers/spree/api/v1/addresses_controller.rb +1 -1
  5. data/app/controllers/spree/api/v1/classifications_controller.rb +1 -1
  6. data/app/controllers/spree/api/v1/images_controller.rb +3 -0
  7. data/app/controllers/spree/api/v1/inventory_units_controller.rb +3 -3
  8. data/app/controllers/spree/api/v1/line_items_controller.rb +3 -0
  9. data/app/controllers/spree/api/v1/option_types_controller.rb +16 -7
  10. data/app/controllers/spree/api/v1/option_values_controller.rb +6 -3
  11. data/app/controllers/spree/api/v1/orders_controller.rb +13 -24
  12. data/app/controllers/spree/api/v1/payments_controller.rb +0 -1
  13. data/app/controllers/spree/api/v1/products_controller.rb +8 -5
  14. data/app/controllers/spree/api/v1/stock_items_controller.rb +1 -1
  15. data/app/controllers/spree/api/v1/stock_locations_controller.rb +1 -1
  16. data/app/controllers/spree/api/v1/tags_controller.rb +28 -0
  17. data/app/controllers/spree/api/v1/taxonomies_controller.rb +7 -4
  18. data/app/controllers/spree/api/v1/taxons_controller.rb +4 -1
  19. data/app/controllers/spree/api/v1/users_controller.rb +5 -3
  20. data/app/controllers/spree/api/v1/zones_controller.rb +3 -3
  21. data/app/helpers/spree/api/api_helpers.rb +4 -1
  22. data/app/models/spree/api_configuration.rb +1 -1
  23. data/app/views/spree/api/errors/invalid_api_key.v1.rabl +1 -1
  24. data/app/views/spree/api/errors/invalid_resource.v1.rabl +1 -1
  25. data/app/views/spree/api/errors/must_specify_api_key.v1.rabl +1 -1
  26. data/app/views/spree/api/errors/not_found.v1.rabl +1 -1
  27. data/app/views/spree/api/errors/unauthorized.v1.rabl +1 -1
  28. data/app/views/spree/api/v1/countries/show.v1.rabl +1 -1
  29. data/app/views/spree/api/v1/line_items/show.v1.rabl +2 -2
  30. data/app/views/spree/api/v1/option_types/show.v1.rabl +1 -1
  31. data/app/views/spree/api/v1/orders/invalid_shipping_method.v1.rabl +1 -1
  32. data/app/views/spree/api/v1/orders/payment.v1.rabl +1 -1
  33. data/app/views/spree/api/v1/orders/show.v1.rabl +9 -9
  34. data/app/views/spree/api/v1/payments/credit_over_limit.v1.rabl +1 -1
  35. data/app/views/spree/api/v1/payments/update_forbidden.v1.rabl +1 -1
  36. data/app/views/spree/api/v1/products/show.v1.rabl +5 -5
  37. data/app/views/spree/api/v1/shipments/cannot_ready_shipment.v1.rabl +1 -1
  38. data/app/views/spree/api/v1/shipments/show.v1.rabl +7 -7
  39. data/app/views/spree/api/v1/shipments/small.v1.rabl +8 -8
  40. data/app/views/spree/api/v1/tags/index.v1.rabl +9 -0
  41. data/app/views/spree/api/v1/taxonomies/jstree.rabl +2 -2
  42. data/app/views/spree/api/v1/taxonomies/nested.v1.rabl +2 -2
  43. data/app/views/spree/api/v1/taxons/jstree.rabl +3 -3
  44. data/app/views/spree/api/v1/taxons/show.v1.rabl +1 -1
  45. data/app/views/spree/api/v1/taxons/taxons.v1.rabl +1 -1
  46. data/app/views/spree/api/v1/users/show.v1.rabl +3 -2
  47. data/app/views/spree/api/v1/variants/big.v1.rabl +3 -3
  48. data/app/views/spree/api/v1/variants/small.v1.rabl +3 -2
  49. data/app/views/spree/api/v1/zones/show.v1.rabl +1 -1
  50. data/config/routes.rb +4 -6
  51. data/db/migrate/20100107141738_add_api_key_to_spree_users.rb +2 -2
  52. data/db/migrate/20120411123334_resize_api_key_field.rb +2 -2
  53. data/db/migrate/20120530054546_rename_api_key_to_spree_api_key.rb +1 -1
  54. data/db/migrate/20131017162334_add_index_to_user_spree_api_key.rb +1 -1
  55. data/lib/spree/api/engine.rb +11 -3
  56. data/lib/spree/api/responders/rabl_template.rb +1 -1
  57. data/lib/spree/api/testing_support/caching.rb +2 -2
  58. data/spec/controllers/spree/api/base_controller_spec.rb +96 -0
  59. data/spec/controllers/spree/api/v1/addresses_controller_spec.rb +56 -0
  60. data/spec/controllers/spree/api/v1/checkouts_controller_spec.rb +363 -0
  61. data/spec/controllers/spree/api/v1/classifications_controller_spec.rb +48 -0
  62. data/spec/controllers/spree/api/v1/countries_controller_spec.rb +48 -0
  63. data/spec/controllers/spree/api/v1/credit_cards_controller_spec.rb +80 -0
  64. data/spec/controllers/spree/api/v1/images_controller_spec.rb +114 -0
  65. data/spec/controllers/spree/api/v1/inventory_units_controller_spec.rb +48 -0
  66. data/spec/controllers/spree/api/v1/line_items_controller_spec.rb +203 -0
  67. data/spec/controllers/spree/api/v1/option_types_controller_spec.rb +122 -0
  68. data/spec/controllers/spree/api/v1/option_values_controller_spec.rb +141 -0
  69. data/spec/controllers/spree/api/v1/orders_controller_spec.rb +735 -0
  70. data/spec/controllers/spree/api/v1/payments_controller_spec.rb +234 -0
  71. data/spec/controllers/spree/api/v1/product_properties_controller_spec.rb +147 -0
  72. data/spec/controllers/spree/api/v1/products_controller_spec.rb +409 -0
  73. data/spec/controllers/spree/api/v1/promotion_application_spec.rb +50 -0
  74. data/spec/controllers/spree/api/v1/promotions_controller_spec.rb +64 -0
  75. data/spec/controllers/spree/api/v1/properties_controller_spec.rb +102 -0
  76. data/spec/controllers/spree/api/v1/return_authorizations_controller_spec.rb +161 -0
  77. data/spec/controllers/spree/api/v1/shipments_controller_spec.rb +187 -0
  78. data/spec/controllers/spree/api/v1/states_controller_spec.rb +86 -0
  79. data/spec/controllers/spree/api/v1/stock_items_controller_spec.rb +143 -0
  80. data/spec/controllers/spree/api/v1/stock_locations_controller_spec.rb +113 -0
  81. data/spec/controllers/spree/api/v1/stock_movements_controller_spec.rb +84 -0
  82. data/spec/controllers/spree/api/v1/stores_controller_spec.rb +133 -0
  83. data/spec/controllers/spree/api/v1/tags_controller_spec.rb +102 -0
  84. data/spec/controllers/spree/api/v1/taxonomies_controller_spec.rb +114 -0
  85. data/spec/controllers/spree/api/v1/taxons_controller_spec.rb +177 -0
  86. data/spec/controllers/spree/api/v1/unauthenticated_products_controller_spec.rb +26 -0
  87. data/spec/controllers/spree/api/v1/users_controller_spec.rb +153 -0
  88. data/spec/controllers/spree/api/v1/variants_controller_spec.rb +205 -0
  89. data/spec/controllers/spree/api/v1/zones_controller_spec.rb +91 -0
  90. data/spec/models/spree/legacy_user_spec.rb +19 -0
  91. data/spec/requests/rabl_cache_spec.rb +32 -0
  92. data/spec/requests/ransackable_attributes_spec.rb +79 -0
  93. data/spec/requests/version_spec.rb +19 -0
  94. data/spec/shared_examples/protect_product_actions.rb +17 -0
  95. data/spec/spec_helper.rb +60 -0
  96. data/spec/support/controller_hacks.rb +40 -0
  97. data/spec/support/database_cleaner.rb +14 -0
  98. data/spec/support/have_attributes_matcher.rb +13 -0
  99. data/spree_api.gemspec +7 -4
  100. metadata +99 -14
@@ -0,0 +1,205 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::V1::VariantsController, type: :controller do
5
+ render_views
6
+
7
+ let(:option_value) { create(:option_value) }
8
+ let!(:product) { create(:product) }
9
+ let!(:variant) do
10
+ variant = product.master
11
+ variant.option_values << option_value
12
+ variant
13
+ end
14
+
15
+ let!(:base_attributes) { Api::ApiHelpers.variant_attributes }
16
+ let!(:show_attributes) { base_attributes.dup.push(:in_stock, :display_price) }
17
+ let!(:new_attributes) { base_attributes }
18
+
19
+ before do
20
+ stub_authentication!
21
+ end
22
+
23
+ it "can see a paginated list of variants" do
24
+ api_get :index
25
+ first_variant = json_response["variants"].first
26
+ expect(first_variant).to have_attributes(show_attributes)
27
+ expect(first_variant["stock_items"]).to be_present
28
+ expect(json_response["count"]).to eq(1)
29
+ expect(json_response["current_page"]).to eq(1)
30
+ expect(json_response["pages"]).to eq(1)
31
+ end
32
+
33
+ it 'can control the page size through a parameter' do
34
+ create(:variant)
35
+ api_get :index, per_page: 1
36
+ expect(json_response['count']).to eq(1)
37
+ expect(json_response['current_page']).to eq(1)
38
+ expect(json_response['pages']).to eq(3)
39
+ end
40
+
41
+ it 'can query the results through a parameter' do
42
+ expected_result = create(:variant, sku: 'FOOBAR')
43
+ api_get :index, q: { sku_cont: 'FOO' }
44
+ expect(json_response['count']).to eq(1)
45
+ expect(json_response['variants'].first['sku']).to eq expected_result.sku
46
+ end
47
+
48
+ it "variants returned contain option values data" do
49
+ api_get :index
50
+ option_values = json_response["variants"].last["option_values"]
51
+ expect(option_values.first).to have_attributes([:name,
52
+ :presentation,
53
+ :option_type_name,
54
+ :option_type_id])
55
+ end
56
+
57
+ it "variants returned contain images data" do
58
+ variant.images.create!(attachment: image("thinking-cat.jpg"))
59
+
60
+ api_get :index
61
+
62
+ expect(json_response["variants"].last).to have_attributes([:images])
63
+ expect(json_response['variants'].first['images'].first).to have_attributes([:attachment_file_name,
64
+ :attachment_width,
65
+ :attachment_height,
66
+ :attachment_content_type,
67
+ :mini_url,
68
+ :small_url,
69
+ :product_url,
70
+ :large_url])
71
+
72
+ end
73
+
74
+ it 'variants returned do not contain cost price data' do
75
+ api_get :index
76
+ expect(json_response["variants"].first.has_key?(:cost_price)).to eq false
77
+ end
78
+
79
+ # Regression test for #2141
80
+ context "a deleted variant" do
81
+ before do
82
+ variant.update_column(:deleted_at, Time.current)
83
+ end
84
+
85
+ it "is not returned in the results" do
86
+ api_get :index
87
+ expect(json_response["variants"].count).to eq(0)
88
+ end
89
+
90
+ it "is not returned even when show_deleted is passed" do
91
+ api_get :index, show_deleted: true
92
+ expect(json_response["variants"].count).to eq(0)
93
+ end
94
+ end
95
+
96
+ context "pagination" do
97
+ it "can select the next page of variants" do
98
+ second_variant = create(:variant)
99
+ api_get :index, page: 2, per_page: 1
100
+ expect(json_response["variants"].first).to have_attributes(show_attributes)
101
+ expect(json_response["total_count"]).to eq(3)
102
+ expect(json_response["current_page"]).to eq(2)
103
+ expect(json_response["pages"]).to eq(3)
104
+ end
105
+ end
106
+
107
+ it "can see a single variant" do
108
+ api_get :show, id: variant.to_param
109
+ expect(json_response).to have_attributes(show_attributes)
110
+ expect(json_response["stock_items"]).to be_present
111
+ option_values = json_response["option_values"]
112
+ expect(option_values.first).to have_attributes([:name,
113
+ :presentation,
114
+ :option_type_name,
115
+ :option_type_id])
116
+ end
117
+
118
+ it "can see a single variant with images" do
119
+ variant.images.create!(attachment: image("thinking-cat.jpg"))
120
+
121
+ api_get :show, id: variant.to_param
122
+
123
+ expect(json_response).to have_attributes(show_attributes + [:images])
124
+ option_values = json_response["option_values"]
125
+ expect(option_values.first).to have_attributes([:name,
126
+ :presentation,
127
+ :option_type_name,
128
+ :option_type_id])
129
+ end
130
+
131
+ it "can learn how to create a new variant" do
132
+ api_get :new
133
+ expect(json_response["attributes"]).to eq(new_attributes.map(&:to_s))
134
+ expect(json_response["required_attributes"]).to be_empty
135
+ end
136
+
137
+ it "cannot create a new variant if not an admin" do
138
+ api_post :create, variant: { sku: "12345" }
139
+ assert_unauthorized!
140
+ end
141
+
142
+ it "cannot update a variant" do
143
+ api_put :update, id: variant.to_param, variant: { sku: "12345" }
144
+ assert_not_found!
145
+ end
146
+
147
+ it "cannot delete a variant" do
148
+ api_delete :destroy, id: variant.to_param
149
+ assert_not_found!
150
+ expect { variant.reload }.not_to raise_error
151
+ end
152
+
153
+ context "as an admin" do
154
+ sign_in_as_admin!
155
+ let(:resource_scoping) { { product_id: variant.product.to_param } }
156
+
157
+ # Test for #2141
158
+ context "deleted variants" do
159
+ before do
160
+ variant.update_column(:deleted_at, Time.current)
161
+ end
162
+
163
+ it "are visible by admin" do
164
+ api_get :index, show_deleted: 1
165
+ expect(json_response["variants"].count).to eq(1)
166
+ end
167
+ end
168
+
169
+ it "can create a new variant" do
170
+ other_value = create(:option_value)
171
+ api_post :create, variant: {
172
+ sku: "12345",
173
+ price: "20",
174
+ option_value_ids: [option_value.id, other_value.id]
175
+ }
176
+
177
+ expect(json_response).to have_attributes(new_attributes)
178
+ expect(response.status).to eq(201)
179
+ expect(json_response["sku"]).to eq("12345")
180
+ expect(json_response["price"]).to match "20"
181
+
182
+ option_value_ids = json_response["option_values"].map { |o| o['id'] }
183
+ expect(option_value_ids).to match_array [option_value.id, other_value.id]
184
+
185
+ expect(variant.product.variants.count).to eq(1)
186
+ end
187
+
188
+ it "can update a variant" do
189
+ api_put :update, id: variant.to_param, variant: { sku: "12345" }
190
+ expect(response.status).to eq(200)
191
+ end
192
+
193
+ it "can delete a variant" do
194
+ api_delete :destroy, id: variant.to_param
195
+ expect(response.status).to eq(204)
196
+ expect { Spree::Variant.find(variant.id) }.to raise_error(ActiveRecord::RecordNotFound)
197
+ end
198
+
199
+ it 'variants returned contain cost price data' do
200
+ api_get :index
201
+ expect(json_response["variants"].first.has_key?(:cost_price)).to eq true
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::V1::ZonesController, type: :controller do
5
+ render_views
6
+
7
+ let!(:attributes) { [:id, :name, :zone_members] }
8
+
9
+ before do
10
+ stub_authentication!
11
+ @zone = create(:zone, name: 'Europe')
12
+ end
13
+
14
+ it "gets list of zones" do
15
+ api_get :index
16
+ expect(json_response['zones'].first).to have_attributes(attributes)
17
+ end
18
+
19
+ it 'can control the page size through a parameter' do
20
+ create(:zone)
21
+ api_get :index, per_page: 1
22
+ expect(json_response['count']).to eq(1)
23
+ expect(json_response['current_page']).to eq(1)
24
+ expect(json_response['pages']).to eq(2)
25
+ end
26
+
27
+ it 'can query the results through a paramter' do
28
+ expected_result = create(:zone, name: 'South America')
29
+ api_get :index, q: { name_cont: 'south' }
30
+ expect(json_response['count']).to eq(1)
31
+ expect(json_response['zones'].first['name']).to eq expected_result.name
32
+ end
33
+
34
+ it "gets a zone" do
35
+ api_get :show, id: @zone.id
36
+ expect(json_response).to have_attributes(attributes)
37
+ expect(json_response['name']).to eq @zone.name
38
+ expect(json_response['zone_members'].size).to eq @zone.zone_members.count
39
+ end
40
+
41
+ context "as an admin" do
42
+ sign_in_as_admin!
43
+
44
+ let!(:country) { create(:country) }
45
+
46
+ it "can create a new zone" do
47
+ params = {
48
+ zone: {
49
+ name: "North Pole",
50
+ zone_members: [
51
+ {
52
+ zoneable_type: "Spree::Country",
53
+ zoneable_id: country.id
54
+ }
55
+ ]
56
+ }
57
+ }
58
+
59
+ api_post :create, params
60
+ expect(response.status).to eq(201)
61
+ expect(json_response).to have_attributes(attributes)
62
+ expect(json_response["zone_members"]).not_to be_empty
63
+ end
64
+
65
+ it "updates a zone" do
66
+ params = { id: @zone.id,
67
+ zone: {
68
+ name: "North Pole",
69
+ zone_members: [
70
+ {
71
+ zoneable_type: "Spree::Country",
72
+ zoneable_id: country.id
73
+ }
74
+ ]
75
+ }
76
+ }
77
+
78
+ api_put :update, params
79
+ expect(response.status).to eq(200)
80
+ expect(json_response['name']).to eq 'North Pole'
81
+ expect(json_response['zone_members']).not_to be_blank
82
+ end
83
+
84
+ it "can delete a zone" do
85
+ api_delete :destroy, id: @zone.id
86
+ expect(response.status).to eq(204)
87
+ expect { @zone.reload }.to raise_error(ActiveRecord::RecordNotFound)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe LegacyUser, type: :model do
5
+ let(:user) { LegacyUser.new }
6
+
7
+ it "can generate an API key" do
8
+ expect(user).to receive(:save!)
9
+ user.generate_spree_api_key!
10
+ expect(user.spree_api_key).not_to be_blank
11
+ end
12
+
13
+ it "can clear an API key" do
14
+ expect(user).to receive(:save!)
15
+ user.clear_spree_api_key!
16
+ expect(user.spree_api_key).to be_blank
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Rabl Cache", type: :request, caching: true do
4
+ let!(:user) { create(:admin_user) }
5
+
6
+ before do
7
+ create(:variant)
8
+ user.generate_spree_api_key!
9
+ expect(Spree::Product.count).to eq(1)
10
+ end
11
+
12
+ it "doesn't create a cache key collision for models with different rabl templates" do
13
+ get "/api/v1/variants", params: { token: user.spree_api_key }
14
+ expect(response.status).to eq(200)
15
+
16
+ # Make sure we get a non master variant
17
+ variant_a = JSON.parse(response.body)['variants'].select do |v|
18
+ !v['is_master']
19
+ end.first
20
+
21
+ expect(variant_a['is_master']).to be false
22
+ expect(variant_a['stock_items']).not_to be_nil
23
+
24
+ get "/api/v1/products/#{Spree::Product.first.id}", params: { token: user.spree_api_key }
25
+ expect(response.status).to eq(200)
26
+ variant_b = JSON.parse(response.body)['variants'].last
27
+ expect(variant_b['is_master']).to be false
28
+
29
+ expect(variant_a['id']).to eq(variant_b['id'])
30
+ expect(variant_b['stock_items']).to be_nil
31
+ end
32
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Ransackable Attributes" do
4
+ let(:user) { create(:user).tap(&:generate_spree_api_key!) }
5
+ let(:order) { create(:order_with_line_items, user: user) }
6
+ context "filtering by attributes one association away" do
7
+ it "does not allow the filtering of variants by order attributes" do
8
+ 2.times { create(:variant) }
9
+
10
+ get "/api/v1/variants?q[orders_email_start]=#{order.email}", params: { token: user.spree_api_key }
11
+
12
+ variants_response = JSON.parse(response.body)
13
+ expect(variants_response['total_count']).to eq(Spree::Variant.count)
14
+ end
15
+ end
16
+
17
+ context "filtering by attributes two associations away" do
18
+ it "does not allow the filtering of variants by user attributes" do
19
+ 2.times { create(:variant) }
20
+
21
+ get "/api/v1/variants?q[orders_user_email_start]=#{order.user.email}", params: { token: user.spree_api_key }
22
+
23
+ variants_response = JSON.parse(response.body)
24
+ expect(variants_response['total_count']).to eq(Spree::Variant.count)
25
+ end
26
+ end
27
+
28
+ context "it maintains desired association behavior" do
29
+ it "allows filtering of variants product name" do
30
+ product = create(:product, name: "Fritos")
31
+ variant = create(:variant, product: product)
32
+ other_variant = create(:variant)
33
+
34
+ get "/api/v1/variants?q[product_name_or_sku_cont]=fritos", params: { token: user.spree_api_key }
35
+
36
+ skus = JSON.parse(response.body)['variants'].map { |variant| variant['sku'] }
37
+ expect(skus).to include variant.sku
38
+ expect(skus).not_to include other_variant.sku
39
+ end
40
+ end
41
+
42
+ context "filtering by attributes" do
43
+ it "most attributes are not filterable by default" do
44
+ product = create(:product, meta_title: "special product")
45
+ other_product = create(:product)
46
+
47
+ get "/api/v1/products?q[meta_title_cont]=special", params: { token: user.spree_api_key }
48
+
49
+ products_response = JSON.parse(response.body)
50
+ expect(products_response['total_count']).to eq(Spree::Product.count)
51
+ end
52
+
53
+ it "id is filterable by default" do
54
+ product = create(:product)
55
+ other_product = create(:product)
56
+
57
+ get "/api/v1/products?q[id_eq]=#{product.id}", params: { token: user.spree_api_key }
58
+
59
+ product_names = JSON.parse(response.body)['products'].map { |product| product['name'] }
60
+ expect(product_names).to include product.name
61
+ expect(product_names).not_to include other_product.name
62
+ end
63
+ end
64
+
65
+ context "filtering by whitelisted attributes" do
66
+ it "filtering is supported for whitelisted attributes" do
67
+ product = create(:product, name: "Fritos")
68
+ other_product = create(:product)
69
+
70
+ get "/api/v1/products?q[name_cont]=fritos", params: { token: user.spree_api_key }
71
+
72
+ product_names = JSON.parse(response.body)['products'].map { |product| product['name'] }
73
+ expect(product_names).to include product.name
74
+ expect(product_names).not_to include other_product.name
75
+ end
76
+ end
77
+
78
+
79
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Version", type: :request do
4
+ let!(:countries) { 2.times.map { create :country } }
5
+
6
+ describe "/api" do
7
+ it "be a redirect" do
8
+ get "/api/countries"
9
+ expect(response).to have_http_status 301
10
+ end
11
+ end
12
+
13
+ describe "/api/v1" do
14
+ it "be successful" do
15
+ get "/api/v1/countries"
16
+ expect(response).to have_http_status 200
17
+ end
18
+ end
19
+ end