spree_api 1.3.1 → 1.3.2
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.
- data/LICENSE +23 -18
- data/app/controllers/spree/api/base_controller.rb +1 -1
- data/app/controllers/spree/api/checkouts_controller.rb +90 -0
- data/app/controllers/spree/api/inventory_units_controller.rb +48 -0
- data/app/controllers/spree/api/orders_controller.rb +0 -17
- data/app/controllers/spree/api/product_properties_controller.rb +3 -2
- data/app/controllers/spree/api/return_authorizations_controller.rb +3 -2
- data/app/controllers/spree/api/taxonomies_controller.rb +3 -2
- data/app/controllers/spree/api/users_controller.rb +51 -0
- data/app/helpers/spree/api/api_helpers.rb +4 -0
- data/app/models/spree/order_decorator.rb +4 -2
- data/app/views/spree/api/images/show.v1.rabl +1 -0
- data/app/views/spree/api/{v1/inventory_units → inventory_units}/show.rabl +0 -0
- data/app/views/spree/api/users/index.v1.rabl +7 -0
- data/app/views/spree/api/users/new.v1.rabl +3 -0
- data/app/views/spree/api/users/show.v1.rabl +3 -0
- data/config/routes.rb +2 -0
- data/lib/spree/api/responders/rabl_template.rb +1 -1
- data/spec/controllers/spree/api/checkouts_controller_spec.rb +102 -0
- data/spec/controllers/spree/api/{v1/inventory_units_controller_spec.rb → inventory_units_controller_spec.rb} +1 -2
- data/spec/controllers/spree/api/orders_controller_spec.rb +1 -74
- data/spec/controllers/spree/api/product_properties_controller_spec.rb +2 -2
- data/spec/controllers/spree/api/users_controller_spec.rb +126 -0
- data/spec/models/spree/order_spec.rb +1 -1
- metadata +19 -11
- data/app/controllers/spree/api/v1/base_controller.rb +0 -111
- data/app/controllers/spree/api/v1/inventory_units_controller.rb +0 -50
data/LICENSE
CHANGED
@@ -1,22 +1,27 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2007-2013, Spree Commerce, Inc. and other contributors
|
2
|
+
All rights reserved.
|
2
3
|
|
3
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
14
|
-
|
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.
|
11
|
-
|
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.
|
10
|
-
|
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).
|
8
|
-
|
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
|
@@ -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].
|
6
|
-
|
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
|
File without changes
|
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
|
@@ -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::
|
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 =>
|
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 =>
|
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.
|
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-
|
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.
|
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.
|
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/
|
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/
|
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/
|
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:
|
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:
|
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/
|
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
|