spree_api 1.0.7 → 1.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +6 -0
- data/LICENSE +19 -23
- data/README.md +22 -10
- data/Rakefile +30 -0
- data/app/controllers/spree/api/v1/base_controller.rb +71 -0
- data/app/controllers/spree/api/v1/images_controller.rb +46 -0
- data/app/controllers/spree/api/v1/line_items_controller.rb +40 -0
- data/app/controllers/spree/api/v1/orders_controller.rb +53 -0
- data/app/controllers/spree/api/v1/products_controller.rb +46 -0
- data/app/controllers/spree/api/v1/variants_controller.rb +56 -0
- data/app/helpers/spree/api/api_helpers.rb +44 -0
- data/app/models/spree/line_item_decorator.rb +3 -0
- data/app/models/spree/option_value_decorator.rb +5 -0
- data/app/models/spree/order_decorator.rb +12 -0
- data/app/models/spree/user_decorator.rb +11 -0
- data/app/views/spree/api/v1/errors/invalid_api_key.rabl +2 -0
- data/app/views/spree/api/v1/errors/invalid_resource.rabl +3 -0
- data/app/views/spree/api/v1/errors/must_specify_api_key.rabl +2 -0
- data/app/views/spree/api/v1/errors/not_found.rabl +2 -0
- data/app/views/spree/api/v1/errors/unauthorized.rabl +2 -0
- data/app/views/spree/api/v1/images/show.rabl +2 -0
- data/app/views/spree/api/v1/line_items/new.rabl +3 -0
- data/app/views/spree/api/v1/line_items/show.rabl +5 -0
- data/app/views/spree/api/v1/orders/address.rabl +0 -0
- data/app/views/spree/api/v1/orders/cart.rabl +0 -0
- data/app/views/spree/api/v1/orders/complete.rabl +0 -0
- data/app/views/spree/api/v1/orders/could_not_transition.rabl +3 -0
- data/app/views/spree/api/v1/orders/delivery.rabl +3 -0
- data/app/views/spree/api/v1/orders/index.rabl +7 -0
- data/app/views/spree/api/v1/orders/invalid_shipping_method.rabl +2 -0
- data/app/views/spree/api/v1/orders/payment.rabl +0 -0
- data/app/views/spree/api/v1/orders/show.rabl +3 -0
- data/app/views/spree/api/v1/products/index.rabl +8 -0
- data/app/views/spree/api/v1/products/new.rabl +3 -0
- data/app/views/spree/api/v1/products/product.rabl +1 -0
- data/app/views/spree/api/v1/products/show.rabl +21 -0
- data/app/views/spree/api/v1/variants/index.rabl +3 -0
- data/app/views/spree/api/v1/variants/new.rabl +2 -0
- data/app/views/spree/api/v1/variants/show.rabl +3 -0
- data/app/views/spree/api/v1/variants/variant.rabl +1 -0
- data/config/locales/en.yml +11 -15
- data/config/routes.rb +14 -28
- data/db/migrate/{20100107141738_add_api_key_to_users.rb → 20100107141738_add_api_key_to_spree_users.rb} +1 -1
- data/lib/spree/api.rb +7 -4
- data/lib/spree/api/controller_setup.rb +27 -0
- data/lib/spree/api/engine.rb +3 -13
- data/lib/spree/api/version.rb +5 -0
- data/lib/spree_api.rb +0 -2
- data/script/rails +5 -0
- data/spec/controllers/spree/api/v1/base_controller_spec.rb +29 -0
- data/spec/controllers/spree/api/v1/images_controller_spec.rb +50 -0
- data/spec/controllers/spree/api/v1/line_items_controller_spec.rb +77 -0
- data/spec/controllers/spree/api/v1/orders_controller_spec.rb +148 -0
- data/spec/controllers/spree/api/v1/products_controller_spec.rb +159 -0
- data/spec/controllers/spree/api/v1/variants_controller_spec.rb +90 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/models/spree/order_spec.rb +18 -0
- data/spec/models/spree/user_spec.rb +19 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/api_helpers.rb +68 -0
- data/spec/support/controller_hacks.rb +27 -0
- data/spree_api.gemspec +24 -0
- metadata +123 -56
- data/app/assets/javascripts/admin/spree.js +0 -4
- data/app/assets/javascripts/admin/spree_api.js +0 -2
- data/app/assets/javascripts/store/spree.js +0 -4
- data/app/assets/javascripts/store/spree_api.js +0 -2
- data/app/assets/stylesheets/admin/spree.css +0 -6
- data/app/assets/stylesheets/admin/spree_api.css +0 -4
- data/app/assets/stylesheets/store/spree.css +0 -6
- data/app/assets/stylesheets/store/spree_api.css +0 -4
- data/app/controllers/spree/admin/users_controller_decorator.rb +0 -17
- data/app/controllers/spree/api/base_controller.rb +0 -172
- data/app/controllers/spree/api/countries_controller.rb +0 -3
- data/app/controllers/spree/api/inventory_units_controller.rb +0 -18
- data/app/controllers/spree/api/line_items_controller.rb +0 -20
- data/app/controllers/spree/api/orders_controller.rb +0 -19
- data/app/controllers/spree/api/products_controller.rb +0 -14
- data/app/controllers/spree/api/shipments_controller.rb +0 -35
- data/app/controllers/spree/api/states_controller.rb +0 -8
- data/app/models/line_item_decorator.rb +0 -7
- data/app/models/order_decorator.rb +0 -9
- data/app/models/shipment_decorator.rb +0 -9
- data/app/models/user_decorator.rb +0 -19
- data/app/overrides/api_admin_user_edit_form.rb +0 -6
- data/app/views/spree/admin/users/_api_fields.html.erb +0 -16
@@ -0,0 +1,44 @@
|
|
1
|
+
module Spree
|
2
|
+
module Api
|
3
|
+
module ApiHelpers
|
4
|
+
def required_fields_for(model)
|
5
|
+
required_fields = model._validators.select do |field, validations|
|
6
|
+
validations.any? { |v| v.is_a?(ActiveModel::Validations::PresenceValidator) }
|
7
|
+
end.map(&:first) # get fields that are invalid
|
8
|
+
# Permalinks presence is validated, but are really automatically generated
|
9
|
+
# Therefore we shouldn't tell API clients that they MUST send one through
|
10
|
+
required_fields.map!(&:to_s).delete("permalink")
|
11
|
+
required_fields
|
12
|
+
end
|
13
|
+
|
14
|
+
def product_attributes
|
15
|
+
[:id, :name, :description, :price,
|
16
|
+
:available_on, :permalink, :count_on_hand, :meta_description, :meta_keywords]
|
17
|
+
end
|
18
|
+
|
19
|
+
def variant_attributes
|
20
|
+
[:id, :name, :count_on_hand, :sku, :price, :weight, :height, :width, :depth, :is_master, :cost_price]
|
21
|
+
end
|
22
|
+
|
23
|
+
def image_attributes
|
24
|
+
[:id, :position, :attachment_content_type, :attachment_file_name, :type, :attachment_updated_at, :attachment_width, :attachment_height, :alt]
|
25
|
+
end
|
26
|
+
|
27
|
+
def option_value_attributes
|
28
|
+
[:id, :name, :presentation, :option_type_name, :option_type_id]
|
29
|
+
end
|
30
|
+
|
31
|
+
def order_attributes
|
32
|
+
[:id, :number, :item_total, :total, :state, :adjustment_total, :credit_total, :user_id, :created_at, :updated_at, :completed_at, :payment_total, :shipment_state, :payment_state, :email, :special_instructions]
|
33
|
+
end
|
34
|
+
|
35
|
+
def line_item_attributes
|
36
|
+
[:quantity, :price, :variant_id]
|
37
|
+
end
|
38
|
+
|
39
|
+
def option_type_attributes
|
40
|
+
[:id, :name, :presentation, :position]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Spree::Order.class_eval do
|
2
|
+
def self.build_from_api(user, params)
|
3
|
+
order = create
|
4
|
+
params[:line_items].each do |variant_id, quantity|
|
5
|
+
line_item_params = { :variant_id => variant_id, :quantity => quantity }
|
6
|
+
line_item = order.add_variant(Spree::Variant.find(variant_id), quantity)
|
7
|
+
end
|
8
|
+
order.user = user
|
9
|
+
order.email = user.email
|
10
|
+
order
|
11
|
+
end
|
12
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
attributes *product_attributes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
object @product
|
2
|
+
attributes *product_attributes
|
3
|
+
child :variants_including_master => :variants do
|
4
|
+
attributes *variant_attributes
|
5
|
+
|
6
|
+
child :option_values => :option_values do
|
7
|
+
attributes *option_value_attributes
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
child :images => :images do
|
12
|
+
attributes *image_attributes
|
13
|
+
end
|
14
|
+
|
15
|
+
child :option_types => :option_types do
|
16
|
+
attributes *option_type_attributes
|
17
|
+
|
18
|
+
child :option_values => :option_values do
|
19
|
+
attributes *option_value_attributes
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
attributes *variant_attributes
|
data/config/locales/en.yml
CHANGED
@@ -1,16 +1,12 @@
|
|
1
|
-
---
|
2
1
|
en:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
no_key: "No key defined"
|
15
|
-
key_generated: "API key generated"
|
16
|
-
key_cleared: "API key cleared"
|
2
|
+
spree:
|
3
|
+
api:
|
4
|
+
must_specify_api_key: "You must specify an API key."
|
5
|
+
invalid_api_key: "Invalid API key (%{key}) specified."
|
6
|
+
unauthorized: "You are not authorized to perform that action."
|
7
|
+
invalid_resource: "Invalid resource. Please fix errors and try again."
|
8
|
+
resource_not_found: "The resource you were looking for could not be found."
|
9
|
+
|
10
|
+
order:
|
11
|
+
could_not_transition: "The order could not be transitioned. Please fix the errors and try again."
|
12
|
+
invalid_shipping_method: "Invalid shipping method specified."
|
data/config/routes.rb
CHANGED
@@ -1,36 +1,22 @@
|
|
1
1
|
Spree::Core::Engine.routes.prepend do
|
2
|
-
namespace :
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
namespace :api do
|
3
|
+
scope :module => :v1 do
|
4
|
+
resources :products do
|
5
|
+
resources :variants
|
6
|
+
resources :images
|
7
7
|
end
|
8
|
-
end
|
9
|
-
end
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
put :event, :on => :member
|
14
|
-
resources :inventory_units, :except => [:new,:edit] do
|
15
|
-
put :event, :on => :member
|
9
|
+
resources :variants, :only => [:index] do
|
10
|
+
resources :images
|
16
11
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
|
13
|
+
resources :orders do
|
14
|
+
member do
|
15
|
+
put :address
|
16
|
+
end
|
17
|
+
|
18
|
+
resources :line_items
|
24
19
|
end
|
25
20
|
end
|
26
|
-
resources :inventory_units, :except => [:new,:edit] do
|
27
|
-
put :event, :on => :member
|
28
|
-
end
|
29
|
-
resources :products, :except => [:new,:edit]
|
30
|
-
resources :countries, :except => [:new,:edit] do
|
31
|
-
resources :states, :except => [:new,:edit]
|
32
|
-
end
|
33
|
-
resources :states, :except => [:new,:edit]
|
34
21
|
end
|
35
|
-
|
36
22
|
end
|
data/lib/spree/api.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'spree/core'
|
2
|
+
require 'spree/auth'
|
3
|
+
|
4
|
+
require 'spree/api/controller_setup'
|
5
|
+
|
6
|
+
require 'rabl'
|
3
7
|
|
4
8
|
module Spree
|
5
9
|
module Api
|
6
|
-
|
7
10
|
end
|
8
11
|
end
|
9
12
|
|
10
|
-
require 'spree/api/engine'
|
13
|
+
require 'spree/api/engine'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spree
|
2
|
+
module Api
|
3
|
+
module ControllerSetup
|
4
|
+
def self.included(klass)
|
5
|
+
klass.class_eval do
|
6
|
+
include AbstractController::Rendering
|
7
|
+
include AbstractController::ViewPaths
|
8
|
+
include AbstractController::Callbacks
|
9
|
+
include AbstractController::Helpers
|
10
|
+
|
11
|
+
include ActiveSupport::Rescuable
|
12
|
+
|
13
|
+
include ActionController::Rendering
|
14
|
+
include ActionController::ImplicitRender
|
15
|
+
include ActionController::Rescue
|
16
|
+
include ActionController::MimeResponds
|
17
|
+
|
18
|
+
include CanCan::ControllerAdditions
|
19
|
+
append_view_path File.expand_path("../../../app/views", File.dirname(__FILE__))
|
20
|
+
append_view_path Rails.root + "app/views"
|
21
|
+
|
22
|
+
respond_to :json
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/spree/api/engine.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rails/engine'
|
2
|
+
|
1
3
|
module Spree
|
2
4
|
module Api
|
3
5
|
class Engine < Rails::Engine
|
@@ -9,20 +11,8 @@ module Spree
|
|
9
11
|
Rails.configuration.cache_classes ? require(c) : load(c)
|
10
12
|
end
|
11
13
|
end
|
12
|
-
|
13
|
-
config.autoload_paths += %W(#{config.root}/lib)
|
14
14
|
config.to_prepare &method(:activate).to_proc
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
15
|
|
19
|
-
|
20
|
-
# Spree::BaseController includes Spree::Core::ControllerHelpers
|
21
|
-
require 'spree/core/controller_helpers'
|
22
|
-
class << Spree::Core::ControllerHelpers
|
23
|
-
def included_with_analytics(receiver)
|
24
|
-
included_without_analytics(receiver)
|
25
|
-
receiver.send :helper, 'spree/analytics'
|
16
|
+
end
|
26
17
|
end
|
27
|
-
alias_method_chain :included, :analytics
|
28
18
|
end
|
data/lib/spree_api.rb
CHANGED
data/script/rails
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spree::Api::V1::BaseController do
|
4
|
+
controller(Spree::Api::V1::BaseController) do
|
5
|
+
def index
|
6
|
+
render :json => { "products" => [] }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context "cannot make a request to the API" do
|
11
|
+
it "without an API key" do
|
12
|
+
api_get :index
|
13
|
+
json_response.should == { "error" => "You must specify an API key." }
|
14
|
+
response.status.should == 401
|
15
|
+
end
|
16
|
+
|
17
|
+
it "with an invalid API key" do
|
18
|
+
request.env["X-Spree-Token"] = "fake_key"
|
19
|
+
get :index, {}
|
20
|
+
json_response.should == { "error" => "Invalid API key (fake_key) specified." }
|
21
|
+
response.status.should == 401
|
22
|
+
end
|
23
|
+
|
24
|
+
it "using an invalid token param" do
|
25
|
+
get :index, :token => "fake_key"
|
26
|
+
json_response.should == { "error" => "Invalid API key (fake_key) specified." }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
describe Spree::Api::V1::ImagesController do
|
5
|
+
render_views
|
6
|
+
|
7
|
+
let!(:product) { Factory(:product) }
|
8
|
+
let!(:attributes) { [:id, :position, :attachment_content_type,
|
9
|
+
:attachment_file_name, :type, :attachment_updated_at, :attachment_width,
|
10
|
+
:attachment_height, :alt] }
|
11
|
+
|
12
|
+
before do
|
13
|
+
stub_authentication!
|
14
|
+
end
|
15
|
+
|
16
|
+
it "can upload a new image for a product" do
|
17
|
+
product.images.count.should == 0
|
18
|
+
api_post :create, :product_id => product.to_param, :image => { :attachment => upload_image("thinking-cat.jpg") }
|
19
|
+
response.status.should == 201
|
20
|
+
json_response.should have_attributes(attributes)
|
21
|
+
product.images.count.should == 1
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can upload a new image for a variant" do
|
25
|
+
product.master.images.count.should == 0
|
26
|
+
api_post :create, :variant_id => product.master.to_param, :image => { :attachment => upload_image("thinking-cat.jpg") }
|
27
|
+
response.status.should == 201
|
28
|
+
json_response.should have_attributes(attributes)
|
29
|
+
product.images.count.should == 1
|
30
|
+
end
|
31
|
+
|
32
|
+
context "working with an existing image" do
|
33
|
+
let!(:product_image) { product.master.images.create!(:attachment => image("thinking-cat.jpg")) }
|
34
|
+
|
35
|
+
it "can update image data" do
|
36
|
+
product_image.position.should == 1
|
37
|
+
api_post :update, :variant_id => product.master.to_param, :image => { :position => 2 }, :id => product_image.id
|
38
|
+
response.status.should == 200
|
39
|
+
json_response.should have_attributes(attributes)
|
40
|
+
product_image.reload.position.should == 2
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can delete an image" do
|
44
|
+
api_delete :destroy, :variant_id => product.master.to_param, :id => product_image.id
|
45
|
+
response.status.should == 200
|
46
|
+
lambda { product_image.reload }.should raise_error(ActiveRecord::RecordNotFound)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|