bulk_api 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/bulk/#resource.rb# +275 -0
  2. metadata +5 -4
@@ -0,0 +1,275 @@
1
+ module Bulk
2
+ class AuthenticationError < StandardError; end
3
+ class AuthorizationError < StandardError; end
4
+
5
+ class Resource
6
+
7
+ attr_reader :controller
8
+ delegate :session, :params, :to => :controller
9
+ delegate :resource_class, :to => "self.class"
10
+ @@resources = []
11
+
12
+ class << self
13
+ attr_writer :application_resource_class
14
+ attr_reader :abstract
15
+ alias_method :abstract?, :abstract
16
+
17
+ def resource_class(klass = nil)
18
+ @resource_class = klass if klass
19
+ @resource_class
20
+ end
21
+
22
+ def resource_name(name = nil)
23
+ @resource_name = name if name
24
+ @resource_name
25
+ end
26
+
27
+ def resources(*resources)
28
+ @@resources = resources unless resources.blank?
29
+ @@resources
30
+ end
31
+
32
+ def application_resource_class
33
+ @application_resource_class ||= ApplicationResource
34
+ @application_resource_class.is_a?(Class) ? @application_resource_class : Object.const_get(@application_resource_class.to_sym)
35
+ end
36
+
37
+ def inherited(base)
38
+ if base.name == application_resource_class.to_s
39
+ base.abstract!
40
+ elsif base.name =~ /(.*)Resource$/
41
+ base.resource_name($1.underscore.pluralize)
42
+ end
43
+ end
44
+
45
+ %w/get create update delete/.each do |method|
46
+ define_method(method) do |controller|
47
+ handle_response(method, controller)
48
+ end
49
+ end
50
+
51
+ def abstract!
52
+ @abstract = true
53
+ @@resources = []
54
+ end
55
+ protected :abstract!
56
+
57
+ private
58
+
59
+ # TODO: refactor this to some kind of Response class
60
+ def handle_response(method, controller)
61
+ response = {}
62
+ application_resource = application_resource_class.new(controller, :abstract => true)
63
+
64
+ if application_resource.respond_to?(:authenticate)
65
+ raise AuthenticationError unless application_resource.authenticate(method)
66
+ end
67
+
68
+ if application_resource.respond_to?(:authorize)
69
+ raise AuthorizationError unless application_resource.authorize(method)
70
+ end
71
+
72
+ controller.params.each do |resource, hash|
73
+ next unless resources.blank? || resources.include?(resource.to_sym)
74
+ resource_object = instantiate_resource_class(controller, resource)
75
+ next unless resource_object
76
+ collection = resource_object.send(method, hash)
77
+ as_json_options = resource_object.send(:as_json_options, resource_object.send(:klass))
78
+ options = {:only_ids => (method == 'delete'), :as_json_options => as_json_options}
79
+ response.deep_merge! collection.to_hash(resource_object.resource_name.to_sym, options)
80
+ end
81
+
82
+ { :json => response }
83
+ rescue AuthenticationError
84
+ { :status => 401, :json => {} }
85
+ rescue AuthorizationError
86
+ { :status => 403, :json => {} }
87
+ end
88
+
89
+ def instantiate_resource_class(controller, resource)
90
+ begin
91
+ "#{resource.to_s.singularize}_resource".classify.constantize.new(controller)
92
+ rescue NameError
93
+ begin
94
+ application_resource_class.new(controller, :resource_name => resource)
95
+ rescue NameError
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ def initialize(controller, options = {})
102
+ @controller = controller
103
+ @resource_name = options[:resource_name].to_s if options[:resource_name]
104
+
105
+ # try to get klass to raise error early if something is not ok
106
+ klass unless options[:abstract]
107
+ end
108
+
109
+ def get(ids = 'all')
110
+ all = ids.to_s == 'all'
111
+ collection = Collection.new
112
+ with_records_auth :get, collection, (all ? nil : ids) do
113
+ records = all ? klass.all : klass.where(:id => ids)
114
+ records.each do |r|
115
+ with_record_auth :get, collection, r.id, r do
116
+ collection.set(r.id, r)
117
+ end
118
+ end
119
+ end
120
+ collection
121
+ end
122
+
123
+ def create(hashes)
124
+ collection = Collection.new
125
+ ids = hashes.map { |r| r[:_local_id] }
126
+ with_records_auth :create, collection, ids do
127
+ hashes.each do |attrs|
128
+ local_id = attrs.delete(:_local_id)
129
+ record = klass.new(filter_params(attrs))
130
+ record[:_local_id] = local_id
131
+ with_record_auth :create, collection, local_id, record do
132
+ record.save
133
+ set_with_validity_check(collection, local_id, record)
134
+ end
135
+ end
136
+ end
137
+ collection
138
+ end
139
+
140
+ def update(hashes)
141
+ collection = Collection.new
142
+ ids = hashes.map { |r| r[:id] }
143
+ with_records_auth :update, collection, ids do
144
+ hashes.each do |attrs|
145
+ attrs.delete(:_local_id)
146
+ record = klass.where(:id => attrs[:id]).first
147
+ with_record_auth :update, collection, record.id, record do
148
+ record.update_attributes(filter_params(attrs))
149
+ set_with_validity_check(collection, record.id, record)
150
+ end
151
+ end
152
+ end
153
+ collection
154
+ end
155
+
156
+ def delete(ids)
157
+ collection = Collection.new
158
+ with_records_auth :delete, collection, ids do
159
+ ids.each do |id|
160
+ record = klass.where(:id => id).first
161
+ with_record_auth :delete, collection, record.id, record do
162
+ record.destroy
163
+ set_with_validity_check(collection, record.id, record)
164
+ end
165
+ end
166
+ end
167
+ collection
168
+ end
169
+
170
+ def resource_name
171
+ @resource_name || self.class.resource_name
172
+ end
173
+
174
+ def as_json_options(klass)
175
+ {}
176
+ end
177
+
178
+ private
179
+ delegate :abstract?, :to => "self.class"
180
+
181
+ def with_record_auth(action, collection, id, record, &block)
182
+ with_record_authentication(action, collection, id, record) do
183
+ with_record_authorization(action, collection, id, record, &block)
184
+ end
185
+ end
186
+
187
+ def with_records_auth(action, collection, ids, &block)
188
+ with_records_authentication(action, collection, ids) do
189
+ with_records_authorization(action, collection, ids, &block)
190
+ end
191
+ end
192
+
193
+ def with_record_authentication(action, collection, id, record)
194
+ authenticated = self.respond_to?(:authenticate_record) ? authenticate_record(action, record) : true
195
+ if authenticated
196
+ yield
197
+ else
198
+ collection.errors.set(id, 'not_authenticated')
199
+ end
200
+ end
201
+
202
+ def with_record_authorization(action, collection, id, record)
203
+ authorized = self.respond_to?(:authorize_record) ? authorize_record(action, record) : true
204
+ if authorized
205
+ yield
206
+ else
207
+ collection.errors.set(id, 'forbidden')
208
+ end
209
+ end
210
+
211
+ def with_records_authentication(action, collection, ids)
212
+ authenticated = self.respond_to?(:authenticate_records) ? authenticate_records(action, klass) : true
213
+ if authenticated
214
+ yield
215
+ else
216
+ ids.each do |id|
217
+ collection.errors.set(id, 'not_authenticated')
218
+ end
219
+ end
220
+ end
221
+
222
+ def with_records_authorization(action, collection, ids)
223
+ authorized = self.respond_to?(:authorize_records) ? authorize_records(action, klass) : true
224
+ if authorized
225
+ yield
226
+ else
227
+ ids.each do |id|
228
+ collection.errors.set(id, 'forbidden')
229
+ end
230
+ end
231
+ end
232
+
233
+ def set_with_validity_check(collection, id, record)
234
+ collection.set(id, record)
235
+ unless record.errors.empty?
236
+ collection.errors.set(id, :invalid, record.errors.to_hash)
237
+ end
238
+ end
239
+
240
+ def filter_params(attributes)
241
+ if self.respond_to?(:params_accessible)
242
+ filter_params_for(:accessible, attributes)
243
+ elsif self.respond_to?(:params_protected)
244
+ filter_params_for(:protected, attributes)
245
+ else
246
+ attributes
247
+ end
248
+ end
249
+
250
+ def filter_params_for(type, attributes)
251
+ filter = send("params_#{type}", klass)
252
+ filter = filter ? filter[resource_name.to_sym] : nil
253
+
254
+ if filter
255
+ attributes.delete_if do |k, v|
256
+ delete_if = filter.include?(k)
257
+ type == :accessible ? !delete_if : delete_if
258
+ end
259
+ end
260
+
261
+ attributes
262
+ end
263
+
264
+
265
+
266
+ def klass
267
+ @_klass ||= begin
268
+ resource_class || (resource_name ? resource_name.to_s.singularize.classify.constantize : nil) ||
269
+ raise("Could not get resource class, please either set resource_class or resource_name that matches model that you want to use")
270
+ rescue NameError
271
+ raise NameError.new("Could not find class matching your resource_name (#{resource_name} - we were looking for #{resource_name.classify})")
272
+ end
273
+ end
274
+ end
275
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: bulk_api
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.3
5
+ version: 0.0.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Piotr Sarnacki
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-16 00:00:00 +02:00
13
+ date: 2011-05-17 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -30,9 +30,9 @@ dependencies:
30
30
  requirement: &id002 !ruby/object:Gem::Requirement
31
31
  none: false
32
32
  requirements:
33
- - - ">="
33
+ - - ~>
34
34
  - !ruby/object:Gem::Version
35
- version: "0"
35
+ version: 1.6.0.rc.1
36
36
  type: :runtime
37
37
  version_requirements: *id002
38
38
  description: Easy integration of rails apps with sproutcore.
@@ -45,6 +45,7 @@ extra_rdoc_files: []
45
45
 
46
46
  files:
47
47
  - app/controllers/bulk/api_controller.rb
48
+ - lib/bulk/#resource.rb#
48
49
  - lib/bulk/abstract_collection.rb
49
50
  - lib/bulk/collection.rb
50
51
  - lib/bulk/engine.rb