Skip to content

Commit

Permalink
Removing order token behavior for a reusable guest_token.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Dutil authored and Jeff Dutil committed Jun 15, 2014
1 parent f41d0cc commit 56dc8e4
Show file tree
Hide file tree
Showing 24 changed files with 129 additions and 139 deletions.
4 changes: 2 additions & 2 deletions api/CHANGELOG.md
Expand Up @@ -9,7 +9,7 @@
Before you'd send a request like this:

```ruby
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => {
:payments_attributes => [{ :payment_method_id => @payment_method.id.to_s }],
:payment_source => { @payment_method.id.to_s => { name: "Spree" } }
Expand All @@ -19,7 +19,7 @@
Now it should look like this:

```ruby
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => {
:payments_attributes => [{ :payment_method_id => @payment_method.id.to_s }]
},
Expand Down
2 changes: 1 addition & 1 deletion api/app/views/spree/api/orders/order.v1.rabl
Expand Up @@ -5,5 +5,5 @@ node(:total_quantity) { |o| o.line_items.sum(:quantity) }
node(:display_total) { |o| o.display_total.to_s }
node(:display_ship_total) { |o| o.display_ship_total }
node(:display_tax_total) { |o| o.display_tax_total }
node(:token) { |o| o.token }
node(:token) { |o| o.guest_token }
node(:checkout_steps) { |o| o.checkout_steps }
4 changes: 2 additions & 2 deletions api/spec/controllers/spree/api/base_controller_spec.rb
Expand Up @@ -26,12 +26,12 @@ def index

context "with a correct order token" do
it "succeeds" do
api_get :index, order_token: order.token, order_id: order.number
api_get :index, order_token: order.guest_token, order_id: order.number
response.status.should == 200
end

it "succeeds with an order_number parameter" do
api_get :index, order_token: order.token, order_number: order.number
api_get :index, order_token: order.guest_token, order_number: order.number
response.status.should == 200
end
end
Expand Down
46 changes: 23 additions & 23 deletions api/spec/controllers/spree/api/checkouts_controller_spec.rb
Expand Up @@ -38,29 +38,29 @@ module Spree
it "should transition a recently created order from cart to address" do
order.state.should eq "cart"
order.email.should_not be_nil
api_put :update, :id => order.to_param, :order_token => order.token
api_put :update, :id => order.to_param, :order_token => order.guest_token
order.reload.state.should eq "address"
end

it "should transition a recently created order from cart to address with order token in header" do
order.state.should eq "cart"
order.email.should_not be_nil
request.headers["X-Spree-Order-Token"] = order.token
request.headers["X-Spree-Order-Token"] = order.guest_token
api_put :update, :id => order.to_param
order.reload.state.should eq "address"
end

it "can take line_items_attributes as a parameter" do
line_item = order.line_items.first
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :line_items_attributes => { 0 => { :id => line_item.id, :quantity => 1 } } }
response.status.should == 200
order.reload.state.should eq "address"
end

it "can take line_items as a parameter" do
line_item = order.line_items.first
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :line_items => { 0 => { :id => line_item.id, :quantity => 1 } } }
response.status.should == 200
order.reload.state.should eq "address"
Expand All @@ -71,7 +71,7 @@ module Spree
order.bill_address = nil
order.save
order.update_column(:state, "address")
api_put :update, :id => order.to_param, :order_token => order.token
api_put :update, :id => order.to_param, :order_token => order.guest_token
# Order has not transitioned
response.status.should == 422
end
Expand All @@ -96,7 +96,7 @@ module Spree

it "can update addresses and transition from address to delivery" do
api_put :update,
:id => order.to_param, :order_token => order.token,
:id => order.to_param, :order_token => order.guest_token,
:order => {
:bill_address_attributes => address,
:ship_address_attributes => address
Expand All @@ -110,7 +110,7 @@ module Spree
# Regression test for #4498
it "does not contain duplicate variant data in delivery return" do
api_put :update,
:id => order.to_param, :order_token => order.token,
:id => order.to_param, :order_token => order.guest_token,
:order => {
:bill_address_attributes => address,
:ship_address_attributes => address
Expand All @@ -127,7 +127,7 @@ module Spree
shipment = create(:shipment, :order => order)
shipment.refresh_rates
shipping_rate = shipment.shipping_rates.where(:selected => false).first
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :shipments_attributes => { "0" => { :selected_shipping_rate_id => shipping_rate.id, :id => shipment.id } } }
response.status.should == 200
# Find the correct shipment...
Expand All @@ -142,7 +142,7 @@ module Spree

it "can update payment method and transition from payment to confirm" do
order.update_column(:state, "payment")
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :payments_attributes => [{ :payment_method_id => @payment_method.id }] }
json_response['state'].should == 'confirm'
json_response['payments'][0]['payment_method']['name'].should == @payment_method.name
Expand All @@ -160,7 +160,7 @@ module Spree
"name" => "Spree Commerce"
}

api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :payments_attributes => [{ :payment_method_id => @payment_method.id.to_s }],
:payment_source => { @payment_method.id.to_s => source_attributes } }
json_response['payments'][0]['payment_method']['name'].should == @payment_method.name
Expand All @@ -170,7 +170,7 @@ module Spree

it "returns errors when source is missing attributes" do
order.update_column(:state, "payment")
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => {
:payments_attributes => [{ :payment_method_id => @payment_method.id.to_s }]
},
Expand All @@ -189,22 +189,22 @@ module Spree
it "can transition from confirm to complete" do
order.update_column(:state, "confirm")
Spree::Order.any_instance.stub(:payment_required? => false)
api_put :update, :id => order.to_param, :order_token => order.token
api_put :update, :id => order.to_param, :order_token => order.guest_token
json_response['state'].should == 'complete'
response.status.should == 200
end

it "returns the order if the order is already complete" do
order.update_column(:state, "complete")
api_put :update, :id => order.to_param, :order_token => order.token
api_put :update, :id => order.to_param, :order_token => order.guest_token
json_response['number'].should == order.number
response.status.should == 200
end

# Regression test for #3784
it "can update the special instructions for an order" do
instructions = "Don't drop it. (Please)"
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :special_instructions => instructions }
expect(json_response['special_instructions']).to eql(instructions)
end
Expand All @@ -214,15 +214,15 @@ module Spree
it "can assign a user to the order" do
user = create(:user)
# Need to pass email as well so that validations succeed
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :user_id => user.id, :email => "guest@spreecommerce.com" }
response.status.should == 200
json_response['user_id'].should == user.id
end
end

it "can assign an email to the order" do
api_put :update, :id => order.to_param, :order_token => order.token,
api_put :update, :id => order.to_param, :order_token => order.guest_token,
:order => { :email => "guest@spreecommerce.com" }
json_response['email'].should == "guest@spreecommerce.com"
response.status.should == 200
Expand All @@ -234,7 +234,7 @@ module Spree
order.update_column(:state, "payment")
PromotionHandler::Coupon.should_receive(:new).with(order).and_call_original
PromotionHandler::Coupon.any_instance.should_receive(:apply).and_return({:coupon_applied? => true})
api_put :update, :id => order.to_param, :order_token => order.token, :order => { :coupon_code => "foobar" }
api_put :update, :id => order.to_param, :order_token => order.guest_token, :order => { :coupon_code => "foobar" }
end
end

Expand All @@ -243,15 +243,15 @@ module Spree
it "cannot transition to address without a line item" do
order.line_items.delete_all
order.update_column(:email, "spree@example.com")
api_put :next, :id => order.to_param, :order_token => order.token
api_put :next, :id => order.to_param, :order_token => order.guest_token
response.status.should == 422
json_response["errors"]["base"].should include(Spree.t(:there_are_no_items_for_this_order))
end

it "can transition an order to the next state" do
order.update_column(:email, "spree@example.com")

api_put :next, :id => order.to_param, :order_token => order.token
api_put :next, :id => order.to_param, :order_token => order.guest_token
response.status.should == 200
json_response['state'].should == 'address'
end
Expand All @@ -262,14 +262,14 @@ module Spree
email: nil
)

api_put :next, :id => order.to_param, :order_token => order.token
api_put :next, :id => order.to_param, :order_token => order.guest_token
response.status.should == 422
json_response['error'].should =~ /could not be transitioned/
end

it "doesnt advance payment state if order has no payment" do
order.update_column(:state, "payment")
api_put :next, :id => order.to_param, :order_token => order.token, :order => {}
api_put :next, :id => order.to_param, :order_token => order.guest_token, :order => {}
json_response["errors"]["base"].should include(Spree.t(:no_payment_found))
end
end
Expand All @@ -279,11 +279,11 @@ module Spree

it 'continues to advance advances an order while it can move forward' do
Spree::Order.any_instance.should_receive(:next).exactly(3).times.and_return(true, true, false)
api_put :advance, :id => order.to_param, :order_token => order.token
api_put :advance, :id => order.to_param, :order_token => order.guest_token
end

it 'returns the order' do
api_put :advance, :id => order.to_param, :order_token => order.token
api_put :advance, :id => order.to_param, :order_token => order.guest_token
json_response['id'].should == order.id
end
end
Expand Down
4 changes: 2 additions & 2 deletions api/spec/controllers/spree/api/line_items_controller_spec.rb
Expand Up @@ -20,14 +20,14 @@ module Spree

context "authenticating with a token" do
it "can add a new line item to an existing order" do
api_post :create, :line_item => { :variant_id => product.master.to_param, :quantity => 1 }, :order_token => order.token
api_post :create, :line_item => { :variant_id => product.master.to_param, :quantity => 1 }, :order_token => order.guest_token
response.status.should == 201
json_response.should have_attributes(attributes)
json_response["variant"]["name"].should_not be_blank
end

it "can add a new line item to an existing order with token in header" do
request.headers["X-Spree-Order-Token"] = order.token
request.headers["X-Spree-Order-Token"] = order.guest_token
api_post :create, :line_item => { :variant_id => product.master.to_param, :quantity => 1 }
response.status.should == 201
json_response.should have_attributes(attributes)
Expand Down
4 changes: 2 additions & 2 deletions api/spec/controllers/spree/api/orders_controller_spec.rb
Expand Up @@ -104,12 +104,12 @@ module Spree
end

it "can view an order if the token is known" do
api_get :show, :id => order.to_param, :order_token => order.token
api_get :show, :id => order.to_param, :order_token => order.guest_token
response.status.should == 200
end

it "can view an order if the token is passed in header" do
request.headers["X-Spree-Order-Token"] = order.token
request.headers["X-Spree-Order-Token"] = order.guest_token
api_get :show, :id => order.to_param
response.status.should == 200
end
Expand Down
4 changes: 2 additions & 2 deletions api/spec/controllers/spree/api/promotion_application_spec.rb
Expand Up @@ -20,7 +20,7 @@ module Spree::Api

it "can apply a coupon code to the order" do
order.total.should == 110.00
api_put :apply_coupon_code, :id => order.to_param, :coupon_code => "10off", :order_token => order.token
api_put :apply_coupon_code, :id => order.to_param, :coupon_code => "10off", :order_token => order.guest_token
response.status.should == 200
order.reload.total.should == 109.00
json_response["success"].should == "The coupon code was successfully applied to your order."
Expand All @@ -36,7 +36,7 @@ module Spree::Api
end

it "fails to apply" do
api_put :apply_coupon_code, :id => order.to_param, :coupon_code => "10off", :order_token => order.token
api_put :apply_coupon_code, :id => order.to_param, :coupon_code => "10off", :order_token => order.guest_token
response.status.should == 422
json_response["success"].should be_blank
json_response["error"].should == "The coupon code is expired"
Expand Down
17 changes: 16 additions & 1 deletion core/CHANGELOG.md
Expand Up @@ -5,10 +5,25 @@

Jordan Brough

* Replaced cookies.signed[:order_id] with cookies.signed[:guest_token].

Now we are using a signed cookie to store the guests unique token
in the browser. This allows customers who close their browser to
continue their shopping when they visit again. More importantly
it allows you as a store owner to uniquely identify your guests orders.
Since we set cookies.signed[:guest_token] whenever a vistor comes
you may also use this cookie token on other objects than just orders.
For instance if a guest user wants to favorite a product you can
assign the cookies.signed[:guest_token] value to a token field on your
favorites model. Which will then allow you to analyze the orders and
favorites this user has placed before which is useful for recommendations.

Jeff Dutil

* Order#token is no longer fetched from another table.

Both Spree::Core::TokeResource and Spree::TokenizedPersmission are deprecated.
Order#token value is now persisted into spree_orders.token. Main motivation
Order#token value is now persisted into spree_orders.guest_token. Main motivation
here is save a few extra queries when creating an order. The TokenResource
module was being of no use in spree core.

Expand Down
4 changes: 2 additions & 2 deletions core/app/models/spree/ability.rb
Expand Up @@ -42,10 +42,10 @@ def initialize(user)
can [:index, :read], OptionValue
can :create, Order
can :read, Order do |order, token|
order.user == user || order.token && token == order.token
order.user == user || order.guest_token && token == order.guest_token
end
can :update, Order do |order, token|
order.user == user || order.token && token == order.token
order.user == user || order.guest_token && token == order.guest_token
end
can [:create, :read], Address
can :update, Address do |address|
Expand Down
5 changes: 4 additions & 1 deletion core/app/models/spree/order.rb
Expand Up @@ -637,7 +637,10 @@ def set_currency
end

def create_token
self.token = ::SecureRandom::hex(8)
self.guest_token ||= loop do
random_token = SecureRandom.urlsafe_base64(nil, false)
break random_token unless self.class.exists?(guest_token: random_token)
end
end
end
end
@@ -1,5 +1,5 @@
class AddTokenToSpreeOrders < ActiveRecord::Migration
def change
add_column :spree_orders, :token, :string
add_column :spree_orders, :guest_token, :string
end
end
Expand Up @@ -8,16 +8,16 @@ def up
when 'SQLite'
Spree::Order.has_one :tokenized_permission, :as => :permissable
Spree::Order.includes(:tokenized_permission).each do |o|
o.update_column :token, o.tokenized_permission.token
o.update_column :guest_token, o.tokenized_permission.token
end
when 'Mysql2'
execute "UPDATE spree_orders, spree_tokenized_permissions
SET spree_orders.token = spree_tokenized_permissions.token
SET spree_orders.guest_token = spree_tokenized_permissions.token
WHERE spree_tokenized_permissions.permissable_id = spree_orders.id
AND spree_tokenized_permissions.permissable_type = 'Spree::Order'"
else
execute "UPDATE spree_orders
SET token = spree_tokenized_permissions.token
SET guest_token = spree_tokenized_permissions.token
FROM spree_tokenized_permissions
WHERE spree_tokenized_permissions.permissable_id = spree_orders.id
AND spree_tokenized_permissions.permissable_type = 'Spree::Order'"
Expand Down

0 comments on commit 56dc8e4

Please sign in to comment.