spree_bushido_api 0.80.27

Sign up to get free protection for your applications and to get access to all the features.
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
+