spree_bushido_api 0.80.27

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 ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2007-2010, Rails Dog LLC and other contributors
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
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.
15
+
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.
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ Spree API
2
+ =========
3
+ Manage orders,shipments etc. with a simple REST API
4
+
5
+ See [RESTful API guide](http://spreecommerce.com/documentation/rest.html) for more details.
6
+
7
+ Testing
8
+ =======
9
+
10
+ Create the test site
11
+
12
+ rake test_app
13
+
14
+ Run the tests
15
+
16
+ rake spec
@@ -0,0 +1,19 @@
1
+ Admin::UsersController.class_eval do
2
+
3
+ before_filter :load_roles, :only => [:edit, :new, :update, :create, :generate_api_key, :clear_api_key]
4
+
5
+ def generate_api_key
6
+ if @user.generate_api_key!
7
+ flash.notice = t('api.key_generated')
8
+ end
9
+ redirect_to edit_admin_user_path(@user)
10
+ end
11
+
12
+ def clear_api_key
13
+ if @user.clear_api_key!
14
+ flash.notice = t('api.key_cleared')
15
+ end
16
+ redirect_to edit_admin_user_path(@user)
17
+ end
18
+
19
+ end
@@ -0,0 +1,174 @@
1
+ class Api::BaseController < Spree::BaseController
2
+ before_filter :check_http_authorization
3
+ before_filter :load_resource
4
+ skip_before_filter :verify_authenticity_token, :if => lambda { admin_token_passed_in_headers }
5
+ authorize_resource
6
+
7
+ respond_to :json
8
+
9
+ def index
10
+ respond_with(@collection) do |format|
11
+ format.json { render :json => @collection.to_json(collection_serialization_options) }
12
+ end
13
+ end
14
+
15
+ def show
16
+ respond_with(@object) do |format|
17
+ format.json { render :json => @object.to_json(object_serialization_options) }
18
+ end
19
+ end
20
+
21
+ def create
22
+ if @object.save
23
+ render :text => "Resource created\n", :status => 201, :location => object_url
24
+ else
25
+ respond_with(@object.errors, :status => 422)
26
+ end
27
+ end
28
+
29
+ def update
30
+ if @object.update_attributes(params[object_name])
31
+ render :nothing => true
32
+ else
33
+ respond_with(@object.errors, :status => 422)
34
+ end
35
+ end
36
+
37
+ def admin_token_passed_in_headers
38
+ request.headers['HTTP_AUTHORIZATION'].present?
39
+ end
40
+
41
+ def access_denied
42
+ render :text => 'access_denied', :status => 401
43
+ end
44
+
45
+ # Generic action to handle firing of state events on an object
46
+ def event
47
+ valid_events = model_class.state_machine.events.map(&:name)
48
+ valid_events_for_object = @object ? @object.state_transitions.map(&:event) : []
49
+
50
+ if params[:e].blank?
51
+ errors = t('api.errors.missing_event')
52
+ elsif valid_events_for_object.include?(params[:e].to_sym)
53
+ @object.send("#{params[:e]}!")
54
+ errors = nil
55
+ elsif valid_events.include?(params[:e].to_sym)
56
+ errors = t('api.errors.invalid_event_for_object', :events => valid_events_for_object.join(','))
57
+ else
58
+ errors = t('api.errors.invalid_event', :events => valid_events.join(','))
59
+ end
60
+
61
+ respond_to do |wants|
62
+ wants.json do
63
+ if errors.blank?
64
+ render :nothing => true
65
+ else
66
+ render :json => errors.to_json, :status => 422
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ protected
73
+ def model_class
74
+ controller_name.classify.constantize
75
+ end
76
+
77
+ def object_name
78
+ controller_name.singularize
79
+ end
80
+
81
+ def load_resource
82
+ if member_action?
83
+ @object ||= load_resource_instance
84
+ instance_variable_set("@#{object_name}", @object)
85
+ else
86
+ @collection ||= collection
87
+ instance_variable_set("@#{controller_name}", @collection)
88
+ end
89
+ end
90
+
91
+ def load_resource_instance
92
+ if new_actions.include?(params[:action].to_sym)
93
+ build_resource
94
+ elsif params[:id]
95
+ find_resource
96
+ end
97
+ end
98
+
99
+ def parent
100
+ nil
101
+ end
102
+
103
+ def find_resource
104
+ if parent.present?
105
+ parent.send(controller_name).find(params[:id])
106
+ else
107
+ model_class.includes(eager_load_associations).find(params[:id])
108
+ end
109
+ end
110
+
111
+ def build_resource
112
+ if parent.present?
113
+ parent.send(controller_name).build(params[object_name])
114
+ else
115
+ model_class.new(params[object_name])
116
+ end
117
+ end
118
+
119
+ def collection
120
+ return @search unless @search.nil?
121
+ params[:search] = {} if params[:search].blank?
122
+ params[:search][:meta_sort] = 'created_at.desc' if params[:search][:meta_sort].blank?
123
+
124
+ scope = parent.present? ? parent.send(controller_name) : model_class.scoped
125
+
126
+ @search = scope.metasearch(params[:search]).relation.limit(100)
127
+ @search
128
+ end
129
+
130
+ def collection_serialization_options
131
+ {}
132
+ end
133
+
134
+ def object_serialization_options
135
+ {}
136
+ end
137
+
138
+ def eager_load_associations
139
+ nil
140
+ end
141
+
142
+ def object_errors
143
+ {:errors => object.errors.full_messages}
144
+ end
145
+
146
+ def object_url(object = nil, options = {})
147
+ target = object ? object : @object
148
+ if parent.present?
149
+ send "admin_#{parent[:model_name]}_#{object_name}_url", parent, target, options
150
+ else
151
+ send "admin_#{object_name}_url", target, options
152
+ end
153
+ end
154
+
155
+ def collection_actions
156
+ [:index]
157
+ end
158
+
159
+ def member_action?
160
+ !collection_actions.include? params[:action].to_sym
161
+ end
162
+
163
+ def new_actions
164
+ [:new, :create]
165
+ end
166
+
167
+ private
168
+ def check_http_authorization
169
+ if request.headers['HTTP_AUTHORIZATION'].blank?
170
+ render :text => "Access Denied\n", :status => 401
171
+ end
172
+ end
173
+
174
+ end
@@ -0,0 +1,3 @@
1
+ class Api::CountriesController < Api::BaseController
2
+ before_filter :access_denied, :except => [:index, :show]
3
+ end
@@ -0,0 +1,19 @@
1
+ class Api::InventoryUnitsController < Api::BaseController
2
+ private
3
+ def parent
4
+ if params[:order_id]
5
+ @parent = Order.find_by_param(params[:order_id])
6
+ elsif params[:shipment_id]
7
+ @parent = Shipment.find_by_param(params[:shipment_id])
8
+ end
9
+ end
10
+
11
+ def parent_data
12
+ [params[:order_id], params[:shipment_id]].compact
13
+ end
14
+
15
+ def eager_load_associations
16
+ [:variant]
17
+ end
18
+
19
+ end
@@ -0,0 +1,22 @@
1
+ class Api::LineItemsController < Api::BaseController
2
+
3
+ private
4
+ def parent
5
+ if params[:order_id]
6
+ @parent ||= Order.find_by_param(params[:order_id])
7
+ end
8
+ end
9
+
10
+ def parent_data
11
+ params[:order_id]
12
+ end
13
+
14
+ def collection_serialization_options
15
+ { :include => [:variant], :methods => [:description] }
16
+ end
17
+
18
+ def object_serialization_options
19
+ collection_serialization_options
20
+ end
21
+
22
+ end
@@ -0,0 +1,20 @@
1
+ class Api::OrdersController < Api::BaseController
2
+ before_filter :access_denied, :except => [:index, :show]
3
+
4
+ private
5
+
6
+ def find_resource
7
+ Order.find_by_param(params[:id])
8
+ end
9
+
10
+ def object_serialization_options
11
+ { :include => {
12
+ :bill_address => {:include => [:country, :state]},
13
+ :ship_address => {:include => [:country, :state]},
14
+ :shipments => {:include => [:shipping_method, :address]},
15
+ :line_items => {:include => [:variant]}
16
+ }
17
+ }
18
+ end
19
+
20
+ end
@@ -0,0 +1,14 @@
1
+ class Api::ProductsController < Api::BaseController
2
+ include Spree::Search
3
+
4
+ private
5
+ def collection
6
+ params[:per_page] ||= 100
7
+ @searcher = Spree::Config.searcher_class.new(params)
8
+ @collection = @searcher.retrieve_products
9
+ end
10
+
11
+ def object_serialization_options
12
+ { :include => [:master, :variants, :taxons] }
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ class Api::ShipmentsController < Api::BaseController
2
+
3
+ private
4
+ def parent
5
+ if params[:order_id]
6
+ @parent ||= Order.find_by_param(params[:order_id])
7
+ end
8
+ end
9
+
10
+ def collection_serialization_options
11
+ { :include => {:shipping_method => {}, :address => {}, :inventory_units => {:include => :variant}},
12
+ :except => [:shipping_method_id, :address_id] }
13
+ end
14
+
15
+ def object_serialization_options
16
+ { :include => {
17
+ :shipping_method => {},
18
+ :address => {:include => [:country, :state]},
19
+ :inventory_units => {
20
+ :include => {
21
+ :variant => {
22
+ :include => {
23
+ :product => {:only => [:name]}
24
+ }
25
+ }
26
+ }
27
+ }
28
+ },
29
+ :except => [:shipping_method_id, :address_id]
30
+ }
31
+ end
32
+
33
+ def eager_load_associations
34
+ [:shipping_method, :address, {:inventory_units => [:variant]}]
35
+ end
36
+
37
+ end
@@ -0,0 +1,8 @@
1
+ class Api::StatesController < Api::BaseController
2
+ before_filter :access_denied, :except => [:index, :show]
3
+
4
+ private
5
+ def parent
6
+ @parent ||= Country.find(params[:country_id])
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ LineItem.class_eval do
2
+ def description
3
+ d = variant.product.name.clone
4
+ d << " (#{variant.options_text})" unless variant.option_values.empty?
5
+ d
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ Order.class_eval do
2
+ def self.find_by_param(param)
3
+ Order.where("id = ? OR number = ?", param, param).first
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ Shipment.class_eval do
2
+ def self.find_by_param(param)
3
+ Shipment.where("id = ? OR number = ?", param, param).first
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ User.class_eval do
2
+
3
+ def clear_api_key!
4
+ self.update_attribute(:authentication_token, "")
5
+ end
6
+
7
+ def generate_api_key!
8
+ self.reset_authentication_token!
9
+ end
10
+
11
+ #def self.authenticate_with_http(username, password)
12
+ # logger.debug(username)
13
+ # self.authenticate_with_token(:auth_token => username)
14
+ #end
15
+
16
+ private
17
+
18
+ def secure_digest(*args)
19
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
20
+ end
21
+
22
+ end
@@ -0,0 +1,16 @@
1
+ <h2><%= t('api.access') %></h2>
2
+
3
+ <% if @user.authentication_token.present? %>
4
+ <p><strong><%= t('api.key') %></strong> <%= @user.authentication_token %></p>
5
+ <%= form_tag clear_api_key_admin_user_path(@user), :method => :put do %>
6
+ <%= button t("api.clear_key") %>
7
+ <% end %>
8
+ <%= form_tag generate_api_key_admin_user_path(@user), :method => :put do %>
9
+ <%= button t("api.regenerate_key") %>
10
+ <% end %>
11
+ <% else %>
12
+ <p><%= t('api.no_key') %></p>
13
+ <%= form_tag generate_api_key_admin_user_path(@user), :method => :put do %>
14
+ <%= button t("api.generate_key") %>
15
+ <% end %>
16
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --strict --tags ~@wip"
5
+ ci_opts = "--format progress --strict"
6
+ %>
7
+ default: <%= std_opts %> features
8
+ wip: --tags @wip:3 --wip features
9
+ ci: <%= ci_opts %> features CI=true
10
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
@@ -0,0 +1,16 @@
1
+ ---
2
+ en:
3
+ api: "API"
4
+ api:
5
+ access: "API Access"
6
+ clear_key: "Clear API key"
7
+ errors:
8
+ invalid_event: "Invalid event name, valid names are %{events}"
9
+ invalid_event_for_object: "Valid event name but not allowed for this object, valid names are %{events}"
10
+ missing_event: "No event name supplied"
11
+ generate_key: "Generate API key"
12
+ key: "API Key"
13
+ regenerate_key: "Regenerate API key"
14
+ no_key: "No key defined"
15
+ key_generated: "API key generated"
16
+ key_cleared: "API key cleared"
data/config/routes.rb ADDED
@@ -0,0 +1,36 @@
1
+ Rails.application.routes.draw do
2
+ namespace :admin do
3
+ resources :users do
4
+ member do
5
+ put :generate_api_key
6
+ put :clear_api_key
7
+ end
8
+ end
9
+ end
10
+
11
+ namespace :api do
12
+ resources :shipments, :except => [:new,:edit] do
13
+ put :event, :on => :member
14
+ resources :inventory_units, :except => [:new,:edit] do
15
+ put :event, :on => :member
16
+ end
17
+ end
18
+ resources :orders, :except => [:new,:edit] do
19
+ put :event, :on => :member
20
+ resources :shipments, :except => [:new,:edit]
21
+ resources :line_items, :except => [:new,:edit]
22
+ resources :inventory_units, :except => [:new,:edit] do
23
+ put :event, :on => :member
24
+ end
25
+ 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
+ end
35
+
36
+ end
@@ -0,0 +1,9 @@
1
+ class AddApiKeyToUsers < ActiveRecord::Migration
2
+ def self.up
3
+ add_column "users", "api_key", :string, :limit => 40
4
+ end
5
+
6
+ def self.down
7
+ remove_column "users", "api_key"
8
+ end
9
+ end
data/lib/spree_api.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'spree_core'
2
+ require 'spree_api_hooks'
3
+
4
+ module SpreeApi
5
+ class Engine < Rails::Engine
6
+ def self.activate
7
+
8
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
9
+ Rails.env.production? ? require(c) : load(c)
10
+ end
11
+
12
+ end
13
+ config.autoload_paths += %W(#{config.root}/lib)
14
+ config.to_prepare &method(:activate).to_proc
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ class ApiHooks < Spree::ThemeSupport::HookListener
2
+ insert_after :admin_user_edit_form, :partial => "admin/users/api_fields"
3
+ end
@@ -0,0 +1,23 @@
1
+ namespace :spree_bushido_api do
2
+ desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
3
+ task :install do
4
+ Rake::Task['spree_bushido_api:install:migrations'].invoke
5
+ Rake::Task['spree_bushido_api:install:assets'].invoke
6
+ end
7
+
8
+ namespace :install do
9
+
10
+ desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
11
+ task :migrations do
12
+ source = File.join(File.dirname(__FILE__), '..', '..', 'db')
13
+ destination = File.join(Rails.root, 'db')
14
+ Spree::FileUtilz.mirror_files(source, destination)
15
+ end
16
+
17
+ desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
18
+ task :assets do
19
+ # No assets
20
+ end
21
+
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spree_bushido_api
3
+ version: !ruby/object:Gem::Version
4
+ hash: 361
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 80
9
+ - 27
10
+ version: 0.80.27
11
+ platform: ruby
12
+ authors:
13
+ - David North
14
+ - Akash Manohar
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-09-01 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: spree_core
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 237
30
+ segments:
31
+ - 0
32
+ - 60
33
+ - 1
34
+ version: 0.60.1
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: spree_bushido_auth
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - "="
44
+ - !ruby/object:Gem::Version
45
+ hash: 361
46
+ segments:
47
+ - 0
48
+ - 80
49
+ - 27
50
+ version: 0.80.27
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description: Required dependancy for Spree
54
+ email: akash@akash.im
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - LICENSE
63
+ - README.md
64
+ - app/controllers/admin/users_controller_decorator.rb
65
+ - app/controllers/api/base_controller.rb
66
+ - app/controllers/api/countries_controller.rb
67
+ - app/controllers/api/inventory_units_controller.rb
68
+ - app/controllers/api/line_items_controller.rb
69
+ - app/controllers/api/orders_controller.rb
70
+ - app/controllers/api/products_controller.rb
71
+ - app/controllers/api/shipments_controller.rb
72
+ - app/controllers/api/states_controller.rb
73
+ - app/models/line_item_decorator.rb
74
+ - app/models/order_decorator.rb
75
+ - app/models/shipment_decorator.rb
76
+ - app/models/user_decorator.rb
77
+ - app/views/admin/users/_api_fields.html.erb
78
+ - config/cucumber.yml
79
+ - config/locales/en.yml
80
+ - config/routes.rb
81
+ - lib/spree_api.rb
82
+ - lib/spree_api_hooks.rb
83
+ - lib/tasks/install.rake
84
+ - db/migrate/20100107141738_add_api_key_to_users.rb
85
+ homepage: http://spreecommerce.com
86
+ licenses: []
87
+
88
+ post_install_message:
89
+ rdoc_options: []
90
+
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 57
99
+ segments:
100
+ - 1
101
+ - 8
102
+ - 7
103
+ version: 1.8.7
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 3
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ requirements:
114
+ - none
115
+ rubyforge_project:
116
+ rubygems_version: 1.8.6
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: Provides RESTful access for Spree.
120
+ test_files: []
121
+