spree_api 1.3.1 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. data/LICENSE +23 -18
  2. data/app/controllers/spree/api/base_controller.rb +1 -1
  3. data/app/controllers/spree/api/checkouts_controller.rb +90 -0
  4. data/app/controllers/spree/api/inventory_units_controller.rb +48 -0
  5. data/app/controllers/spree/api/orders_controller.rb +0 -17
  6. data/app/controllers/spree/api/product_properties_controller.rb +3 -2
  7. data/app/controllers/spree/api/return_authorizations_controller.rb +3 -2
  8. data/app/controllers/spree/api/taxonomies_controller.rb +3 -2
  9. data/app/controllers/spree/api/users_controller.rb +51 -0
  10. data/app/helpers/spree/api/api_helpers.rb +4 -0
  11. data/app/models/spree/order_decorator.rb +4 -2
  12. data/app/views/spree/api/images/show.v1.rabl +1 -0
  13. data/app/views/spree/api/{v1/inventory_units → inventory_units}/show.rabl +0 -0
  14. data/app/views/spree/api/users/index.v1.rabl +7 -0
  15. data/app/views/spree/api/users/new.v1.rabl +3 -0
  16. data/app/views/spree/api/users/show.v1.rabl +3 -0
  17. data/config/routes.rb +2 -0
  18. data/lib/spree/api/responders/rabl_template.rb +1 -1
  19. data/spec/controllers/spree/api/checkouts_controller_spec.rb +102 -0
  20. data/spec/controllers/spree/api/{v1/inventory_units_controller_spec.rb → inventory_units_controller_spec.rb} +1 -2
  21. data/spec/controllers/spree/api/orders_controller_spec.rb +1 -74
  22. data/spec/controllers/spree/api/product_properties_controller_spec.rb +2 -2
  23. data/spec/controllers/spree/api/users_controller_spec.rb +126 -0
  24. data/spec/models/spree/order_spec.rb +1 -1
  25. metadata +19 -11
  26. data/app/controllers/spree/api/v1/base_controller.rb +0 -111
  27. data/app/controllers/spree/api/v1/inventory_units_controller.rb +0 -50
data/LICENSE CHANGED
@@ -1,22 +1,27 @@
1
- Copyright (c) 2012 Ryan Bigg
1
+ Copyright (c) 2007-2013, Spree Commerce, Inc. and other contributors
2
+ All rights reserved.
2
3
 
3
- MIT License
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
4
6
 
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Spree nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
12
15
 
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
27
 
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -53,7 +53,7 @@ module Spree
53
53
 
54
54
  def authenticate_user
55
55
  if requires_authentication? || api_key.present?
56
- unless @current_api_user = Spree.user_class.find_by_spree_api_key(api_key)
56
+ unless @current_api_user = Spree.user_class.find_by_spree_api_key(api_key.to_s)
57
57
  render "spree/api/errors/invalid_api_key", :status => 401 and return
58
58
  end
59
59
  else
@@ -0,0 +1,90 @@
1
+ module Spree
2
+ module Api
3
+ class CheckoutsController < Spree::Api::BaseController
4
+ before_filter :load_order, :only => :update
5
+ before_filter :associate_user, :only => :update
6
+
7
+ include Spree::Core::ControllerHelpers::Auth
8
+ include Spree::Core::ControllerHelpers::Order
9
+
10
+ respond_to :json
11
+
12
+ def create
13
+ @order = Order.build_from_api(current_api_user, nested_params)
14
+ next!(:status => 201)
15
+ end
16
+
17
+ def update
18
+ if @order.update_attributes(object_params)
19
+ state_callback(:after) if @order.next
20
+ respond_with(@order, :default_template => 'spree/api/orders/show')
21
+ else
22
+ respond_with(@order, :default_template => 'spree/api/orders/could_not_transition', :status => 422)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def object_params
29
+ # For payment step, filter order parameters to produce the expected nested attributes for a single payment and its source, discarding attributes for payment methods other than the one selected
30
+ if @order.payment?
31
+ if params[:payment_source].present? && source_params = params.delete(:payment_source)[params[:order][:payments_attributes].first[:payment_method_id].underscore]
32
+ params[:order][:payments_attributes].first[:source_attributes] = source_params
33
+ end
34
+ if params[:order].present? && params[:order][:payments_attributes]
35
+ params[:order][:payments_attributes].first[:amount] = @order.total
36
+ end
37
+ end
38
+ params[:order]
39
+ end
40
+
41
+ def nested_params
42
+ map_nested_attributes_keys Order, params[:order] || {}
43
+ end
44
+
45
+ # Should be overriden if you have areas of your checkout that don't match
46
+ # up to a step within checkout_steps, such as a registration step
47
+ def skip_state_validation?
48
+ false
49
+ end
50
+
51
+ def load_order
52
+ @order = Spree::Order.find_by_number!(params[:id])
53
+ raise_insufficient_quantity and return if @order.insufficient_stock_lines.present?
54
+ @order.state = params[:state] if params[:state]
55
+ state_callback(:before)
56
+ end
57
+
58
+ def raise_insufficient_quantity
59
+ respond_with(@order, :default_template => 'spree/api/orders/insufficient_quantity')
60
+ end
61
+
62
+ def state_callback(before_or_after = :before)
63
+ method_name = :"#{before_or_after}_#{@order.state}"
64
+ send(method_name) if respond_to?(method_name, true)
65
+ end
66
+
67
+ def before_address
68
+ @order.bill_address ||= Address.default
69
+ @order.ship_address ||= Address.default
70
+ end
71
+
72
+ def before_delivery
73
+ return if params[:order].present?
74
+ @order.shipping_method ||= (@order.rate_hash.first && @order.rate_hash.first[:shipping_method])
75
+ end
76
+
77
+ def before_payment
78
+ @order.payments.destroy_all if request.put?
79
+ end
80
+
81
+ def next!(options={})
82
+ if @order.valid? && @order.next
83
+ render 'spree/api/orders/show', :status => options[:status] || 200
84
+ else
85
+ render 'spree/api/orders/could_not_transition', :status => 422
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,48 @@
1
+ module Spree
2
+ module Api
3
+ class InventoryUnitsController < Spree::Api::BaseController
4
+ before_filter :prepare_event, :only => :update
5
+
6
+ def show
7
+ @inventory_unit = inventory_unit
8
+ end
9
+
10
+ def update
11
+ authorize! :update, Order
12
+
13
+ inventory_unit.transaction do
14
+ if inventory_unit.update_attributes(params[:inventory_unit])
15
+ fire
16
+ render :show, :status => 200
17
+ else
18
+ invalid_resource!(inventory_unit)
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def inventory_unit
26
+ @inventory_unit ||= InventoryUnit.find(params[:id])
27
+ end
28
+
29
+ def prepare_event
30
+ return unless @event = params[:fire]
31
+
32
+ can_event = "can_#{@event}?"
33
+
34
+ unless inventory_unit.respond_to?(can_event) &&
35
+ inventory_unit.send(can_event)
36
+ render :text => { :exception => "cannot transition to #{@event}" }.to_json,
37
+ :status => 200
38
+ false
39
+ end
40
+ end
41
+
42
+ def fire
43
+ inventory_unit.send("#{@event}!") if @event
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -31,23 +31,6 @@ module Spree
31
31
  end
32
32
  end
33
33
 
34
- def address
35
- order.build_ship_address(params[:shipping_address]) if params[:shipping_address]
36
- order.build_bill_address(params[:billing_address]) if params[:billing_address]
37
- next!
38
- end
39
-
40
- def delivery
41
- begin
42
- ShippingMethod.find(params[:shipping_method_id])
43
- rescue ActiveRecord::RecordNotFound
44
- render :invalid_shipping_method, :status => 422
45
- else
46
- order.update_attribute(:shipping_method_id, params[:shipping_method_id])
47
- next!
48
- end
49
- end
50
-
51
34
  def cancel
52
35
  order.cancel!
53
36
  render :show
@@ -7,8 +7,9 @@ module Spree
7
7
  before_filter :product_property, :only => [:show, :update, :destroy]
8
8
 
9
9
  def index
10
- @product_properties = @product.product_properties.ransack(params[:q]).result
11
- .page(params[:page]).per(params[:per_page])
10
+ @product_properties = @product.product_properties.
11
+ ransack(params[:q]).result.
12
+ page(params[:page]).per(params[:per_page])
12
13
  respond_with(@product_properties)
13
14
  end
14
15
 
@@ -6,8 +6,9 @@ module Spree
6
6
  before_filter :authorize_admin!
7
7
 
8
8
  def index
9
- @return_authorizations = order.return_authorizations.ransack(params[:q]).result
10
- .page(params[:page]).per(params[:per_page])
9
+ @return_authorizations = order.return_authorizations.
10
+ ransack(params[:q]).result.
11
+ page(params[:page]).per(params[:per_page])
11
12
  respond_with(@return_authorizations)
12
13
  end
13
14
 
@@ -4,8 +4,9 @@ module Spree
4
4
  respond_to :json
5
5
 
6
6
  def index
7
- @taxonomies = Taxonomy.order('name').includes(:root => :children).ransack(params[:q]).result
8
- .page(params[:page]).per(params[:per_page])
7
+ @taxonomies = Taxonomy.order('name').includes(:root => :children).
8
+ ransack(params[:q]).result.
9
+ page(params[:page]).per(params[:per_page])
9
10
  respond_with(@taxonomies)
10
11
  end
11
12
 
@@ -0,0 +1,51 @@
1
+ module Spree
2
+ module Api
3
+ class UsersController < Spree::Api::BaseController
4
+ respond_to :json
5
+
6
+ def index
7
+ @users = Spree.user_class.accessible_by(current_ability,:read).ransack(params[:q]).result.page(params[:page]).per(params[:per_page])
8
+ respond_with(@users)
9
+ end
10
+
11
+ def show
12
+ authorize! :show, user
13
+ respond_with(user)
14
+ end
15
+
16
+ def new
17
+ end
18
+
19
+ def create
20
+ authorize! :create, Spree.user_class
21
+ @user = Spree.user_class.new(params[:user])
22
+ if @user.save
23
+ respond_with(@user, :status => 201, :default_template => :show)
24
+ else
25
+ invalid_resource!(@user)
26
+ end
27
+ end
28
+
29
+ def update
30
+ authorize! :update, user
31
+ if user.update_attributes(params[:user])
32
+ respond_with(user, :status => 200, :default_template => :show)
33
+ else
34
+ invalid_resource!(user)
35
+ end
36
+ end
37
+
38
+ def destroy
39
+ authorize! :destroy, user
40
+ user.destroy
41
+ respond_with(user, :status => 204)
42
+ end
43
+
44
+ private
45
+
46
+ def user
47
+ @user ||= Spree.user_class.find(params[:id])
48
+ end
49
+ end
50
+ end
51
+ end
@@ -76,6 +76,10 @@ module Spree
76
76
  def country_attributes
77
77
  [:id, :iso_name, :iso, :iso3, :name, :numcode]
78
78
  end
79
+
80
+ def user_attributes
81
+ [:id, :email, :created_at, :updated_at]
82
+ end
79
83
  end
80
84
  end
81
85
  end
@@ -2,8 +2,10 @@ Spree::Order.class_eval do
2
2
  def self.build_from_api(user, params)
3
3
  order = create
4
4
  params[:line_items_attributes] ||= []
5
- params[:line_items_attributes].each do |line_item|
6
- order.add_variant(Spree::Variant.find(line_item[:variant_id]), line_item[:quantity])
5
+ unless params[:line_items_attributes].empty?
6
+ params[:line_items_attributes].each_key do |k|
7
+ order.add_variant(Spree::Variant.find(params[:line_items_attributes][k][:variant_id]), params[:line_items_attributes][k][:quantity])
8
+ end
7
9
  end
8
10
 
9
11
  order.user = user
@@ -1,3 +1,4 @@
1
1
  object @image
2
2
  attributes *image_attributes
3
3
  attributes :viewable_type, :viewable_id
4
+ node(:attachment_url) { |i| i.attachment.to_s }
@@ -0,0 +1,7 @@
1
+ object false
2
+ child(@users => :users) do
3
+ extends "spree/api/users/show"
4
+ end
5
+ node(:count) { @users.count }
6
+ node(:current_page) { params[:page] || 1 }
7
+ node(:pages) { @users.num_pages }
@@ -0,0 +1,3 @@
1
+ object false
2
+ node(:attributes) { [*user_attributes] }
3
+ node(:required_attributes) { required_fields_for(Spree.user_class) }
@@ -0,0 +1,3 @@
1
+ object @user
2
+
3
+ attributes *user_attributes
data/config/routes.rb CHANGED
@@ -15,6 +15,7 @@ Spree::Core::Engine.routes.prepend do
15
15
  end
16
16
 
17
17
  resources :images
18
+ resources :checkouts
18
19
  resources :variants, :only => [:index] do
19
20
  end
20
21
 
@@ -53,5 +54,6 @@ Spree::Core::Engine.routes.prepend do
53
54
  resources :taxons
54
55
  end
55
56
  resources :inventory_units, :only => [:show, :update]
57
+ resources :users
56
58
  end
57
59
  end
@@ -4,7 +4,7 @@ module Spree
4
4
  module RablTemplate
5
5
  def to_format
6
6
  if template
7
- render template.to_sym, :status => options[:status] || 200
7
+ render template, :status => options[:status] || 200
8
8
  else
9
9
  super
10
10
  end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::CheckoutsController do
5
+ render_views
6
+
7
+ before(:each) do
8
+ stub_authentication!
9
+ Spree::Config[:track_inventory_levels] = false
10
+ country_zone = create(:zone, :name => 'CountryZone')
11
+ @state = create(:state)
12
+ @country = @state.country
13
+ country_zone.members.create(:zoneable => @country)
14
+
15
+ @shipping_method = create(:shipping_method, :zone => country_zone)
16
+ @payment_method = create(:payment_method)
17
+ end
18
+
19
+ after do
20
+ Spree::Config[:track_inventory_levels] = true
21
+ end
22
+
23
+ context "POST 'create'" do
24
+ it "creates a new order when no parameters are passed" do
25
+ api_post :create
26
+
27
+ json_response['number'].should be_present
28
+ response.status.should == 201
29
+ end
30
+ end
31
+
32
+ context "PUT 'update'" do
33
+ let(:order) { create(:order) }
34
+
35
+ before(:each) do
36
+ Order.any_instance.stub(:confirmation_required? => true)
37
+ Order.any_instance.stub(:payment_required? => true)
38
+ end
39
+
40
+ it "will return an error if the order cannot transition" do
41
+ order.update_column(:state, "address")
42
+ api_put :update, :id => order.to_param
43
+ json_response['error'].should =~ /could not be transitioned/
44
+ response.status.should == 422
45
+ end
46
+
47
+ it "can update addresses and transition from address to delivery" do
48
+ order.update_column(:state, "address")
49
+ shipping_address = billing_address = {
50
+ :firstname => 'John',
51
+ :lastname => 'Doe',
52
+ :address1 => '7735 Old Georgetown Road',
53
+ :city => 'Bethesda',
54
+ :phone => '3014445002',
55
+ :zipcode => '20814',
56
+ :state_id => @state.id,
57
+ :country_id => @country.id
58
+ }
59
+ api_put :update,
60
+ :id => order.to_param,
61
+ :order => { :bill_address_attributes => billing_address, :ship_address_attributes => shipping_address }
62
+
63
+ json_response['state'].should == 'delivery'
64
+ json_response['bill_address']['firstname'].should == 'John'
65
+ json_response['ship_address']['firstname'].should == 'John'
66
+ response.status.should == 200
67
+ end
68
+
69
+ it "can update shipping method and transition from delivery to payment" do
70
+ order.update_column(:state, "delivery")
71
+ api_put :update, :id => order.to_param, :order => { :shipping_method_id => @shipping_method.id }
72
+
73
+ json_response['shipments'][0]['shipping_method']['name'].should == @shipping_method.name
74
+ json_response['state'].should == 'payment'
75
+ response.status.should == 200
76
+ end
77
+
78
+ it "can update payment method and transition from payment to confirm" do
79
+ order.update_column(:state, "payment")
80
+ api_put :update, :id => order.to_param, :order => { :payments_attributes => [{ :payment_method_id => @payment_method.id }] }
81
+ json_response['state'].should == 'confirm'
82
+ json_response['payments'][0]['payment_method']['name'].should == @payment_method.name
83
+ response.status.should == 200
84
+ end
85
+
86
+ it "can transition from confirm to complete" do
87
+ order.update_column(:state, "confirm")
88
+ Spree::Order.any_instance.stub(:payment_required? => false)
89
+ api_put :update, :id => order.to_param
90
+ json_response['state'].should == 'complete'
91
+ response.status.should == 200
92
+ end
93
+
94
+ it "returns the order if the order is already complete" do
95
+ order.update_column(:state, "complete")
96
+ api_put :update, :id => order.to_param
97
+ json_response['number'].should == order.number
98
+ response.status.should == 200
99
+ end
100
+ end
101
+ end
102
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Spree
4
- describe Api::V1::InventoryUnitsController do
4
+ describe Api::InventoryUnitsController do
5
5
  render_views
6
6
 
7
7
  before do
@@ -41,6 +41,5 @@ module Spree
41
41
  json_response['exception'].should match /cannot transition to bad/
42
42
  end
43
43
  end
44
-
45
44
  end
46
45
  end
@@ -53,14 +53,9 @@ module Spree
53
53
  assert_unauthorized!
54
54
  end
55
55
 
56
- it "cannot change delivery information on an order that doesn't belong to them" do
57
- api_put :delivery, :id => order.to_param
58
- assert_unauthorized!
59
- end
60
-
61
56
  it "can create an order" do
62
57
  variant = create(:variant)
63
- api_post :create, :order => { :line_items => [{ :variant_id => variant.to_param, :quantity => 5 }] }
58
+ api_post :create, :order => { :line_items => { "0" => { :variant_id => variant.to_param, :quantity => 5 } } }
64
59
  response.status.should == 201
65
60
  order = Order.last
66
61
  order.line_items.count.should == 1
@@ -97,52 +92,6 @@ module Spree
97
92
  let!(:shipping_method) { create(:shipping_method) }
98
93
  let!(:payment_method) { create(:payment_method) }
99
94
 
100
- it "can add address information to an order" do
101
- api_put :address, :id => order.to_param, :shipping_address => shipping_address, :billing_address => billing_address
102
-
103
- response.status.should == 200
104
- order.reload
105
- order.shipping_address.reload
106
- order.billing_address.reload
107
- # We can assume the rest of the parameters are set if these two are
108
- order.shipping_address.firstname.should == shipping_address[:firstname]
109
- order.billing_address.firstname.should == billing_address[:firstname]
110
- order.state.should == "delivery"
111
- json_response["shipping_methods"].should_not be_empty
112
- end
113
-
114
- it "can add just shipping address information to an order" do
115
- api_put :address, :id => order.to_param, :shipping_address => shipping_address
116
- response.status.should == 200
117
- order.reload
118
- order.shipping_address.reload
119
- order.shipping_address.firstname.should == shipping_address[:firstname]
120
- order.bill_address.should be_nil
121
- end
122
-
123
- it "cannot use an address that has no valid shipping methods" do
124
- shipping_method.destroy
125
- api_put :address, :id => order.to_param, :shipping_address => shipping_address, :billing_address => billing_address
126
- response.status.should == 422
127
- json_response["errors"]["base"].should == ["No shipping methods available for selected location, please change your address and try again."]
128
- end
129
-
130
- it "can not add invalid ship address information to an order" do
131
- shipping_address[:firstname] = ""
132
- api_put :address, :id => order.to_param, :shipping_address => shipping_address, :billing_address => billing_address
133
-
134
- response.status.should == 422
135
- json_response["errors"]["ship_address.firstname"].should_not be_blank
136
- end
137
-
138
- it "can not add invalid ship address information to an order" do
139
- billing_address[:firstname] = ""
140
- api_put :address, :id => order.to_param, :shipping_address => shipping_address, :billing_address => billing_address
141
-
142
- response.status.should == 422
143
- json_response["errors"]["bill_address.firstname"].should_not be_blank
144
- end
145
-
146
95
  it "can add line items" do
147
96
  api_put :update, :id => order.to_param, :order => { :line_items => [{:variant_id => create(:variant).id, :quantity => 2}] }
148
97
 
@@ -155,28 +104,6 @@ module Spree
155
104
  order.line_items << create(:line_item)
156
105
  end
157
106
 
158
- context "for delivery" do
159
- before do
160
- order.update_attribute(:state, "delivery")
161
- end
162
-
163
- it "can select a shipping method for an order" do
164
- order.shipping_method.should be_nil
165
- api_put :delivery, :id => order.to_param, :shipping_method_id => shipping_method.id
166
- response.status.should == 200
167
- order.reload
168
- order.state.should == "payment"
169
- order.shipping_method.should == shipping_method
170
- end
171
-
172
- it "cannot select an invalid shipping method for an order" do
173
- order.shipping_method.should be_nil
174
- api_put :delivery, :id => order.to_param, :shipping_method_id => '1234567890'
175
- response.status.should == 422
176
- json_response["errors"].should include("Invalid shipping method specified.")
177
- end
178
- end
179
-
180
107
  it "can empty an order" do
181
108
  api_put :empty, :id => order.to_param
182
109
  response.status.should == 200
@@ -6,8 +6,8 @@ module Spree
6
6
  render_views
7
7
 
8
8
  let!(:product) { create(:product) }
9
- let!(:property_1) {product.product_properties.create(:property_name => "My Property 1", :value => "my value 1")}
10
- let!(:property_2) {product.product_properties.create(:property_name => "My Property 2", :value => "my value 2")}
9
+ let!(:property_1) {product.product_properties.create(:property_name => "My Property 1", :value => "my value 1", :position => 0)}
10
+ let!(:property_2) {product.product_properties.create(:property_name => "My Property 2", :value => "my value 2", :position => 1)}
11
11
 
12
12
  let(:attributes) { [:id, :product_id, :property_id, :value, :property_name] }
13
13
  let(:resource_scoping) { { :product_id => product.to_param } }
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Api::UsersController do
5
+ render_views
6
+
7
+ let(:user) { create(:user) }
8
+ let(:stranger) { create(:user, :email => 'stranger@example.com') }
9
+ let(:attributes) { [:id, :email, :created_at, :updated_at] }
10
+
11
+ before { stub_authentication! }
12
+
13
+ context "as a normal user" do
14
+ before { Spree::LegacyUser.stub :find_by_spree_api_key => user }
15
+
16
+ it "can get own details" do
17
+ api_get :show, :id => user.id
18
+
19
+ json_response['email'].should eq user.email
20
+ end
21
+
22
+ it "cannot get other users details" do
23
+ api_get :show, :id => stranger.id
24
+
25
+ assert_unauthorized!
26
+ end
27
+
28
+ it "can learn how to create a new user" do
29
+ api_get :new
30
+ json_response["attributes"].should == attributes.map(&:to_s)
31
+ end
32
+
33
+ it "can create a new user" do
34
+ api_post :create, :user => { :email => 'new@example.com', :password => 'spree123', :password_confirmation => 'spree123' }
35
+ json_response['email'].should eq 'new@example.com'
36
+ end
37
+
38
+ # there's no validations on LegacyUser?
39
+ xit "cannot create a new user with invalid attributes" do
40
+ api_post :create, :user => {}
41
+ response.status.should == 422
42
+ json_response["error"].should == "Invalid resource. Please fix errors and try again."
43
+ errors = json_response["errors"]
44
+ end
45
+
46
+ it "can update own details" do
47
+ api_put :update, :id => user.id, :user => { :email => "mine@example.com" }
48
+ json_response['email'].should eq 'mine@example.com'
49
+ end
50
+
51
+ it "cannot update other users details" do
52
+ api_put :update, :id => stranger.id, :user => { :email => "mine@example.com" }
53
+ assert_unauthorized!
54
+ end
55
+
56
+ it "can delete itself" do
57
+ api_delete :destroy, :id => user.id
58
+ response.status.should == 204
59
+ end
60
+
61
+ it "cannot delete other user" do
62
+ api_delete :destroy, :id => stranger.id
63
+ assert_unauthorized!
64
+ end
65
+
66
+ it "should only get own details on index" do
67
+ 2.times { create(:user) }
68
+ api_get :index
69
+
70
+ Spree.user_class.count.should eq 3
71
+ json_response['count'].should eq 1
72
+ json_response['users'].size.should eq 1
73
+ end
74
+ end
75
+
76
+ context "as an admin" do
77
+ sign_in_as_admin!
78
+
79
+ it "gets all users" do
80
+ Spree::LegacyUser.stub :find_by_spree_api_key => current_api_user
81
+
82
+ 2.times { create(:user) }
83
+
84
+ api_get :index
85
+ Spree.user_class.count.should eq 2
86
+ json_response['count'].should eq 2
87
+ json_response['users'].size.should eq 2
88
+ end
89
+
90
+ it 'can control the page size through a parameter' do
91
+ 2.times { create(:user) }
92
+ api_get :index, :per_page => 1
93
+ json_response['count'].should == 1
94
+ json_response['current_page'].should == 1
95
+ json_response['pages'].should == 2
96
+ end
97
+
98
+ it 'can query the results through a paramter' do
99
+ expected_result = create(:user, :email => 'brian@spreecommerce.com')
100
+ api_get :index, :q => { :email_cont => 'brian' }
101
+ json_response['count'].should == 1
102
+ json_response['users'].first['email'].should eq expected_result.email
103
+ end
104
+
105
+ it "can create" do
106
+ api_post :create, :user => { :email => "new@example.com", :password => 'spree123', :password_confirmation => 'spree123' }
107
+ json_response.should have_attributes(attributes)
108
+ response.status.should == 201
109
+ end
110
+
111
+ it "can destroy user without orders" do
112
+ user.orders.destroy_all
113
+ api_delete :destroy, :id => user.id
114
+ response.status.should == 204
115
+ end
116
+
117
+ it "cannot destroy user with orders" do
118
+ create(:completed_order_with_totals, :user => user)
119
+ api_delete :destroy, :id => user.id
120
+ json_response["exception"].should eq "Spree::LegacyUser::DestroyWithOrdersError"
121
+ response.status.should == 422
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -7,7 +7,7 @@ module Spree
7
7
  it 'can build an order from API parameters' do
8
8
  product = Spree::Product.create!(:name => 'Test', :sku => 'TEST-1', :price => 33.22)
9
9
  variant_id = product.master.id
10
- order = Order.build_from_api(user, { :line_items_attributes => [{ :variant_id => variant_id, :quantity => 5 }]})
10
+ order = Order.build_from_api(user, { :line_items_attributes => { "0" => { :variant_id => variant_id, :quantity => 5 }}})
11
11
 
12
12
  order.user.should == user
13
13
  line_item = order.line_items.first
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-06 00:00:00.000000000 Z
12
+ date: 2013-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: spree_core
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.3.1
21
+ version: 1.3.2
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 1.3.1
29
+ version: 1.3.2
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: versioncake
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -89,8 +89,10 @@ files:
89
89
  - Rakefile
90
90
  - app/controllers/spree/api/addresses_controller.rb
91
91
  - app/controllers/spree/api/base_controller.rb
92
+ - app/controllers/spree/api/checkouts_controller.rb
92
93
  - app/controllers/spree/api/countries_controller.rb
93
94
  - app/controllers/spree/api/images_controller.rb
95
+ - app/controllers/spree/api/inventory_units_controller.rb
94
96
  - app/controllers/spree/api/line_items_controller.rb
95
97
  - app/controllers/spree/api/orders_controller.rb
96
98
  - app/controllers/spree/api/payments_controller.rb
@@ -100,8 +102,7 @@ files:
100
102
  - app/controllers/spree/api/shipments_controller.rb
101
103
  - app/controllers/spree/api/taxonomies_controller.rb
102
104
  - app/controllers/spree/api/taxons_controller.rb
103
- - app/controllers/spree/api/v1/base_controller.rb
104
- - app/controllers/spree/api/v1/inventory_units_controller.rb
105
+ - app/controllers/spree/api/users_controller.rb
105
106
  - app/controllers/spree/api/variants_controller.rb
106
107
  - app/controllers/spree/api/zones_controller.rb
107
108
  - app/helpers/spree/api/api_helpers.rb
@@ -122,6 +123,7 @@ files:
122
123
  - app/views/spree/api/errors/not_found.v1.rabl
123
124
  - app/views/spree/api/errors/unauthorized.v1.rabl
124
125
  - app/views/spree/api/images/show.v1.rabl
126
+ - app/views/spree/api/inventory_units/show.rabl
125
127
  - app/views/spree/api/line_items/new.v1.rabl
126
128
  - app/views/spree/api/line_items/show.v1.rabl
127
129
  - app/views/spree/api/orders/address.v1.rabl
@@ -158,7 +160,9 @@ files:
158
160
  - app/views/spree/api/taxons/new.v1.rabl
159
161
  - app/views/spree/api/taxons/show.v1.rabl
160
162
  - app/views/spree/api/taxons/taxons.v1.rabl
161
- - app/views/spree/api/v1/inventory_units/show.rabl
163
+ - app/views/spree/api/users/index.v1.rabl
164
+ - app/views/spree/api/users/new.v1.rabl
165
+ - app/views/spree/api/users/show.v1.rabl
162
166
  - app/views/spree/api/variants/index.v1.rabl
163
167
  - app/views/spree/api/variants/new.v1.rabl
164
168
  - app/views/spree/api/variants/show.v1.rabl
@@ -183,8 +187,10 @@ files:
183
187
  - script/rails
184
188
  - spec/controllers/spree/api/addresses_controller_spec.rb
185
189
  - spec/controllers/spree/api/base_controller_spec.rb
190
+ - spec/controllers/spree/api/checkouts_controller_spec.rb
186
191
  - spec/controllers/spree/api/countries_controller_spec.rb
187
192
  - spec/controllers/spree/api/images_controller_spec.rb
193
+ - spec/controllers/spree/api/inventory_units_controller_spec.rb
188
194
  - spec/controllers/spree/api/line_items_controller_spec.rb
189
195
  - spec/controllers/spree/api/orders_controller_spec.rb
190
196
  - spec/controllers/spree/api/payments_controller_spec.rb
@@ -195,7 +201,7 @@ files:
195
201
  - spec/controllers/spree/api/taxonomies_controller_spec.rb
196
202
  - spec/controllers/spree/api/taxons_controller_spec.rb
197
203
  - spec/controllers/spree/api/unauthenticated_products_controller_spec.rb
198
- - spec/controllers/spree/api/v1/inventory_units_controller_spec.rb
204
+ - spec/controllers/spree/api/users_controller_spec.rb
199
205
  - spec/controllers/spree/api/variants_controller_spec.rb
200
206
  - spec/controllers/spree/api/zones_controller_spec.rb
201
207
  - spec/fixtures/thinking-cat.jpg
@@ -221,7 +227,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
221
227
  version: '0'
222
228
  segments:
223
229
  - 0
224
- hash: -4546587640053475121
230
+ hash: 2361962546786859221
225
231
  required_rubygems_version: !ruby/object:Gem::Requirement
226
232
  none: false
227
233
  requirements:
@@ -230,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
236
  version: '0'
231
237
  segments:
232
238
  - 0
233
- hash: -4546587640053475121
239
+ hash: 2361962546786859221
234
240
  requirements: []
235
241
  rubyforge_project:
236
242
  rubygems_version: 1.8.23
@@ -240,8 +246,10 @@ summary: Spree's API
240
246
  test_files:
241
247
  - spec/controllers/spree/api/addresses_controller_spec.rb
242
248
  - spec/controllers/spree/api/base_controller_spec.rb
249
+ - spec/controllers/spree/api/checkouts_controller_spec.rb
243
250
  - spec/controllers/spree/api/countries_controller_spec.rb
244
251
  - spec/controllers/spree/api/images_controller_spec.rb
252
+ - spec/controllers/spree/api/inventory_units_controller_spec.rb
245
253
  - spec/controllers/spree/api/line_items_controller_spec.rb
246
254
  - spec/controllers/spree/api/orders_controller_spec.rb
247
255
  - spec/controllers/spree/api/payments_controller_spec.rb
@@ -252,7 +260,7 @@ test_files:
252
260
  - spec/controllers/spree/api/taxonomies_controller_spec.rb
253
261
  - spec/controllers/spree/api/taxons_controller_spec.rb
254
262
  - spec/controllers/spree/api/unauthenticated_products_controller_spec.rb
255
- - spec/controllers/spree/api/v1/inventory_units_controller_spec.rb
263
+ - spec/controllers/spree/api/users_controller_spec.rb
256
264
  - spec/controllers/spree/api/variants_controller_spec.rb
257
265
  - spec/controllers/spree/api/zones_controller_spec.rb
258
266
  - spec/fixtures/thinking-cat.jpg
@@ -1,111 +0,0 @@
1
- module Spree
2
- module Api
3
- module V1
4
- class BaseController < ActionController::Metal
5
- include Spree::Api::ControllerSetup
6
-
7
- attr_accessor :current_api_user
8
-
9
- before_filter :set_content_type
10
- before_filter :check_for_api_key, :if => :requires_authentication?
11
- before_filter :authenticate_user
12
-
13
- rescue_from Exception, :with => :error_during_processing
14
- rescue_from CanCan::AccessDenied, :with => :unauthorized
15
- rescue_from ActiveRecord::RecordNotFound, :with => :not_found
16
-
17
- helper Spree::Api::ApiHelpers
18
-
19
- def map_nested_attributes_keys(klass, attributes)
20
- nested_keys = klass.nested_attributes_options.keys
21
- attributes.inject({}) do |h, (k,v)|
22
- key = nested_keys.include?(k.to_sym) ? "#{k}_attributes" : k
23
- h[key] = v
24
- h
25
- end.with_indifferent_access
26
- end
27
-
28
- private
29
-
30
- def set_content_type
31
- content_type = case params[:format]
32
- when "json"
33
- "application/json"
34
- when "xml"
35
- "text/xml"
36
- end
37
- headers["Content-Type"] = content_type
38
- end
39
-
40
- def check_for_api_key
41
- render "spree/api/v1/errors/must_specify_api_key", :status => 401 and return if api_key.blank?
42
- end
43
-
44
- def authenticate_user
45
- if requires_authentication? || api_key.present?
46
- unless @current_api_user = Spree.user_class.find_by_spree_api_key(api_key)
47
- render "spree/api/v1/errors/invalid_api_key", :status => 401 and return
48
- end
49
- else
50
- # Effectively, an anonymous user
51
- @current_api_user = Spree.user_class.new
52
- end
53
- end
54
-
55
- def unauthorized
56
- render "spree/api/v1/errors/unauthorized", :status => 401 and return
57
- end
58
-
59
- def requires_authentication?
60
- Spree::Api::Config[:requires_authentication]
61
- end
62
-
63
- def not_found
64
- render "spree/api/v1/errors/not_found", :status => 404 and return
65
- end
66
-
67
- def error_during_processing(exception)
68
- render :text => { exception: exception.message }.to_json,
69
- :status => 422 and return
70
- end
71
-
72
- def current_ability
73
- Spree::Ability.new(current_api_user)
74
- end
75
-
76
- def invalid_resource!(resource)
77
- @resource = resource
78
- render "spree/api/v1/errors/invalid_resource", :status => 422
79
- end
80
-
81
- def api_key
82
- request.headers["X-Spree-Token"] || params[:token]
83
- end
84
- helper_method :api_key
85
-
86
- def find_product(id)
87
- begin
88
- product_scope.find_by_permalink!(id.to_s)
89
- rescue ActiveRecord::RecordNotFound
90
- product_scope.find(id)
91
- end
92
- end
93
-
94
- def product_scope
95
- if current_api_user.has_spree_role?("admin")
96
- scope = Product
97
- unless params[:show_deleted]
98
- scope = scope.not_deleted
99
- end
100
- else
101
- scope = Product.active
102
- end
103
-
104
- scope.includes(:master)
105
- end
106
-
107
- end
108
- end
109
- end
110
- end
111
-
@@ -1,50 +0,0 @@
1
- module Spree
2
- module Api
3
- module V1
4
- class InventoryUnitsController < Spree::Api::V1::BaseController
5
- before_filter :prepare_event, :only => :update
6
-
7
- def show
8
- @inventory_unit = inventory_unit
9
- end
10
-
11
- def update
12
- authorize! :update, Order
13
-
14
- inventory_unit.transaction do
15
- if inventory_unit.update_attributes(params[:inventory_unit])
16
- fire
17
- render :show, :status => 200
18
- else
19
- invalid_resource!(inventory_unit)
20
- end
21
- end
22
- end
23
-
24
- private
25
-
26
- def inventory_unit
27
- @inventory_unit ||= InventoryUnit.find(params[:id])
28
- end
29
-
30
- def prepare_event
31
- return unless @event = params[:fire]
32
-
33
- can_event = "can_#{@event}?"
34
-
35
- unless inventory_unit.respond_to?(can_event) &&
36
- inventory_unit.send(can_event)
37
- render :text => { exception: "cannot transition to #{@event}" }.to_json,
38
- :status => 200
39
- false
40
- end
41
- end
42
-
43
- def fire
44
- inventory_unit.send("#{@event}!") if @event
45
- end
46
-
47
- end
48
- end
49
- end
50
- end