rest-sinatra 0.3.3 → 0.4.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.4.0
data/lib/rest-sinatra.rb CHANGED
@@ -20,6 +20,7 @@ module RestSinatra
20
20
 
21
21
  def _resource(name, resource_type, &block)
22
22
  config = evaluate_block(name, resource_type, &block)
23
+ config[:resource] = self
23
24
  validate(config)
24
25
  build_resource(config)
25
26
  config
@@ -30,13 +31,15 @@ module RestSinatra
30
31
  scope.extend(ResourceMethods)
31
32
  scope.instance_eval do
32
33
  @c = {
33
- :name => name,
34
- :resource_type => resource_type,
35
- :model => nil,
36
- :read_only => [],
37
- :permission => nil,
38
- :callbacks => {},
39
- :nested_resources => []
34
+ :name => name,
35
+ :resource_type => resource_type,
36
+ :model => nil,
37
+ :read_only => [],
38
+ :resource => nil,
39
+ :permission_to_view => nil,
40
+ :permission_to_modify => nil,
41
+ :callbacks => {},
42
+ :nested_resources => []
40
43
  }
41
44
  end
42
45
  scope.instance_eval(&block)
@@ -66,36 +69,51 @@ module RestSinatra
66
69
  end
67
70
 
68
71
  def build_parent_resource(config)
69
- callbacks = config[:callbacks]
70
- model = config[:model]
71
- name = config[:name]
72
- read_only = config[:read_only]
72
+ callbacks = config[:callbacks]
73
+ model = config[:model]
74
+ name = config[:name]
75
+ permission_to_view = config[:permission_to_view]
76
+ permission_to_modify = config[:permission_to_modify]
77
+ read_only = config[:read_only]
78
+ resource = config[:resource]
73
79
 
74
80
  get '/?' do
75
- require_at_least(:basic)
81
+ permission_check(
82
+ :default => :basic,
83
+ :override => permission_to_view
84
+ )
76
85
  validate_before_find_all(params, model)
77
- @documents = find_with_filters(params, model)
78
- @documents.render
86
+ documents = find_with_filters(params, model)
87
+ permitted = documents.select { |document| resource.permit_view?(@current_user, document) }
88
+ sanitized = permitted.map { |document| resource.sanitize(@current_user, document) }
89
+ sanitized.render
79
90
  end
80
91
 
81
92
  get '/:id/?' do |id|
82
- require_at_least(:basic)
93
+ permission_check(
94
+ :default => :basic,
95
+ :override => permission_to_view
96
+ )
83
97
  id = params.delete("id")
84
98
  validate_before_find_one(params, model)
85
- @document = find_document!(model, id)
86
- @document.render
99
+ document = find_document!(model, id)
100
+ unauthorized_api_key! unless resource.permit_view?(@current_user, document)
101
+ sanitized = resource.sanitize(@current_user, document)
102
+ sanitized.render
87
103
  end
88
104
 
89
105
  post '/?' do
90
- require_at_least(:curator)
106
+ permission_check(
107
+ :default => :admin,
108
+ :override => permission_to_modify
109
+ )
110
+ unauthorized_api_key! unless resource.permit_modify?(@current_user, nil)
91
111
  validate_before_create(params, model, read_only)
92
112
  callback(callbacks[:before_save])
93
113
  callback(callbacks[:before_create])
94
114
  @document = model.new(params)
95
- unless @document.valid?
96
- error 400, { "errors" => @document.errors.errors }.to_json
97
- end
98
- error 500, [].to_json unless @document.save
115
+ invalid_document! unless @document.valid?
116
+ internal_server_error! unless @document.save
99
117
  callback(callbacks[:after_create])
100
118
  callback(callbacks[:after_save])
101
119
  response.status = 201
@@ -104,25 +122,31 @@ module RestSinatra
104
122
  end
105
123
 
106
124
  put '/:id/?' do
107
- require_at_least(:curator)
125
+ permission_check(
126
+ :default => :admin,
127
+ :override => permission_to_modify
128
+ )
108
129
  id = params.delete("id")
109
130
  @document = find_document!(model, id)
131
+ unauthorized_api_key! unless resource.permit_modify?(@current_user, @document)
110
132
  validate_before_update(params, model, read_only)
111
133
  callback(callbacks[:before_save])
112
134
  callback(callbacks[:before_update])
113
135
  @document = model.update(id, params)
114
- unless @document.valid?
115
- error 400, { "errors" => @document.errors.errors }.to_json
116
- end
136
+ invalid_document! unless @document.valid?
117
137
  callback(callbacks[:after_update])
118
138
  callback(callbacks[:after_save])
119
139
  @document.render
120
140
  end
121
141
 
122
142
  delete '/:id/?' do
123
- require_at_least(:curator)
143
+ permission_check(
144
+ :default => :admin,
145
+ :override => permission_to_modify
146
+ )
124
147
  id = params.delete("id")
125
148
  @document = find_document!(model, id)
149
+ unauthorized_api_key! unless resource.permit_modify?(@current_user, @document)
126
150
  callback(callbacks[:before_destroy])
127
151
  @document.destroy
128
152
  callback(callbacks[:after_destroy])
@@ -132,7 +156,7 @@ module RestSinatra
132
156
  helpers do
133
157
  def find_document!(model, id)
134
158
  document = model.find_by_id(id)
135
- error 404, [].to_json unless document
159
+ not_found! unless document
136
160
  document
137
161
  end
138
162
  end
@@ -151,44 +175,67 @@ module RestSinatra
151
175
  # klass : nested resource class
152
176
  # association : a method on the parent model that will return child models
153
177
  def build_nested_resource(klass, association, parent_config, child_config)
154
- callbacks = child_config[:callbacks]
155
- child_model = child_config[:model]
156
- child_name = child_config[:name]
157
- permission = child_config[:permission]
158
- read_only = child_config[:read_only]
178
+ callbacks = child_config[:callbacks]
179
+ child_model = child_config[:model]
180
+ child_name = child_config[:name]
181
+ child_resource = child_config[:resource]
182
+ permission_to_view = child_config[:permission_to_view]
183
+ permission_to_modify = child_config[:permission_to_modify]
184
+ read_only = child_config[:read_only]
159
185
 
160
186
  parent_model = parent_config[:model]
161
187
  parent_name = parent_config[:name]
188
+ parent_resource = parent_config[:resource]
162
189
 
163
190
  get "/:parent_id/#{child_name}/?" do
191
+ permission_check(
192
+ :default => :basic,
193
+ :override => permission_to_view
194
+ )
164
195
  parent_id = params.delete("parent_id")
165
- permission_check(:basic, permission, parent_id)
166
- @parent_document = find_parent!(parent_model, parent_id)
167
- all_child_documents = @parent_document.send(association)
196
+ parent_document = find_parent!(parent_model, parent_id)
197
+ unauthorized_api_key! unless parent_resource.permit_view?(@current_user, parent_document)
198
+ all_child_documents = parent_document.send(association)
168
199
  validate_before_find_all(params, child_model) # ?
169
- @child_documents = nested_find_with_filters(all_child_documents, params, parent_model)
170
- @child_documents.render
200
+ child_documents = nested_find_with_filters(all_child_documents, params, parent_model)
201
+ permitted = child_documents.select do |child_document|
202
+ child_resource.permit_view?(@current_user, child_document)
203
+ end
204
+ sanitized = permitted.map { |document| child_resource.sanitize(@current_user, document) }
205
+ sanitized.render
171
206
  end
172
207
 
173
208
  get "/:parent_id/#{child_name}/:child_id/?" do
209
+ permission_check(
210
+ :default => :basic,
211
+ :override => permission_to_view
212
+ )
174
213
  parent_id = params.delete("parent_id")
175
- permission_check(:basic, permission, parent_id)
176
214
  child_id = params.delete("child_id")
177
215
  validate_before_find_one(params, child_model) # ?
178
- @parent_document, @child_document = find_documents!(parent_model, parent_id, association, child_id)
179
- @child_document.render
216
+ parent_document = find_parent!(parent_model, parent_id)
217
+ unauthorized_api_key! unless parent_resource.permit_view?(@current_user, parent_document)
218
+ child_document = find_child!(parent_document, association, child_id)
219
+ unauthorized_api_key! unless child_resource.permit_view?(@current_user, child_document)
220
+ sanitized = child_resource.sanitize(@current_user, child_document)
221
+ sanitized.render
180
222
  end
181
223
 
182
224
  post "/:parent_id/#{child_name}/?" do
225
+ permission_check(
226
+ :default => :admin,
227
+ :override => permission_to_modify
228
+ )
183
229
  parent_id = params.delete("parent_id")
184
- permission_check(:curator, permission, parent_id)
185
230
  @parent_document = find_parent!(parent_model, parent_id)
231
+ unauthorized_api_key! unless parent_resource.permit_modify?(@current_user, @parent_document)
232
+ unauthorized_api_key! unless child_resource.permit_modify?(@current_user, nil)
186
233
  validate_before_create(params, child_model, read_only)
187
234
  callback(callbacks[:before_save])
188
235
  callback(callbacks[:before_create])
189
236
  @child_document = child_model.new(params)
190
237
  @parent_document.send(association) << @child_document
191
- error 500, [].to_json unless @parent_document.save
238
+ internal_server_error! unless @parent_document.save
192
239
  callback(callbacks[:after_create])
193
240
  callback(callbacks[:after_save])
194
241
  response.status = 201
@@ -199,52 +246,58 @@ module RestSinatra
199
246
  end
200
247
 
201
248
  put "/:parent_id/#{child_name}/:child_id/?" do
249
+ permission_check(
250
+ :default => :admin,
251
+ :override => permission_to_modify
252
+ )
202
253
  parent_id = params.delete("parent_id")
203
- permission_check(:curator, permission, parent_id)
204
254
  child_id = params.delete("child_id")
205
- @parent_document, @child_document = find_documents!(parent_model, parent_id, association, child_id)
255
+ @parent_document = find_parent!(parent_model, parent_id)
256
+ unauthorized_api_key! unless parent_resource.permit_modify?(@current_user, @parent_document)
257
+ @child_document = find_child!(@parent_document, association, child_id)
258
+ unauthorized_api_key! unless child_resource.permit_modify?(@current_user, @child_document)
206
259
  validate_before_update(params, child_model, read_only)
207
260
  callback(callbacks[:before_save])
208
261
  callback(callbacks[:before_update])
209
262
  @child_document.attributes = params
210
263
  child_index = @parent_document.send(association).index(@child_document)
211
264
  @parent_document.send(association)[child_index] = @child_document
212
- error 500, [].to_json unless @parent_document.save
265
+ internal_server_error! unless @parent_document.save
213
266
  callback(callbacks[:after_update])
214
267
  callback(callbacks[:after_save])
215
268
  @child_document.render
216
269
  end
217
270
 
218
271
  delete "/:parent_id/#{child_name}/:child_id/?" do
272
+ permission_check(
273
+ :default => :admin,
274
+ :override => permission_to_modify
275
+ )
219
276
  parent_id = params.delete("parent_id")
220
- permission_check(:curator, permission, parent_id)
221
277
  child_id = params.delete("child_id")
222
- @parent_document, @child_document = find_documents!(parent_model, parent_id, association, child_id)
278
+ @parent_document = find_parent!(parent_model, parent_id)
279
+ unauthorized_api_key! unless parent_resource.permit_modify?(@current_user, @parent_document)
280
+ @child_document = find_child!(@parent_document, association, child_id)
281
+ unauthorized_api_key! unless child_resource.permit_modify?(@current_user, @child_document)
223
282
  callback(callbacks[:before_destroy])
224
283
  @parent_document.send(association).delete(@child_document)
225
284
  callback(callbacks[:after_destroy])
226
- error 500, [].to_json unless @parent_document.save
285
+ internal_server_error! unless @parent_document.save
227
286
  { "id" => child_id }.to_json
228
287
  end
229
288
 
230
289
  helpers do
231
290
  def find_parent!(parent_model, parent_id)
232
291
  parent_document = parent_model.find_by_id(parent_id)
233
- error 404, [].to_json unless parent_document
292
+ not_found! unless parent_document
234
293
  parent_document
235
294
  end
236
295
 
237
296
  def find_child!(parent_document, association, child_id)
238
297
  child_document = parent_document.send(association).detect { |x| x.id == child_id }
239
- error 404, [].to_json unless child_document
298
+ not_found! unless child_document
240
299
  child_document
241
300
  end
242
-
243
- def find_documents!(parent_model, parent_id, association, child_id)
244
- parent_document = find_parent!(parent_model, parent_id)
245
- child_document = find_child!(parent_document, association, child_id)
246
- [parent_document, child_document]
247
- end
248
301
  end
249
302
  end
250
303
 
@@ -269,9 +322,14 @@ module RestSinatra
269
322
  @c[:read_only] << attribute
270
323
  end
271
324
 
272
- def permission(level)
273
- raise "permission already declared" if @c[:permission]
274
- @c[:permission] = level
325
+ def permission_to_view(level)
326
+ raise "permission already declared" if @c[:permission_to_view]
327
+ @c[:permission_to_view] = level
328
+ end
329
+
330
+ def permission_to_modify(level)
331
+ raise "permission already declared" if @c[:permission_to_modify]
332
+ @c[:permission_to_modify] = level
275
333
  end
276
334
 
277
335
  def callback(name, &block)
data/rest-sinatra.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rest-sinatra}
8
- s.version = "0.3.3"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["David James"]
12
- s.date = %q{2009-10-11}
12
+ s.date = %q{2009-10-14}
13
13
  s.description = %q{Provides a DSL for making RESTful Sinatra actions with MongoMapper models.}
14
14
  s.email = %q{djames@sunlightfoundation.com}
15
15
  s.extra_rdoc_files = [
@@ -8,5 +8,8 @@ class Sources
8
8
 
9
9
  @r = resource "sources" do
10
10
  model Source
11
+
12
+ permission_to_view :basic
13
+ permission_to_modify :owner
11
14
  end
12
15
  end
@@ -17,6 +17,10 @@ describe "Posts" do
17
17
  @config[:model].should == Post
18
18
  end
19
19
 
20
+ it "resource should be Posts" do
21
+ @config[:resource].should == Posts
22
+ end
23
+
20
24
  it "read_only should be correct" do
21
25
  @config[:read_only].should == [:created_at, :updated_at]
22
26
  end
@@ -133,6 +137,10 @@ describe "Comments" do
133
137
  @config[:model].should == Comment
134
138
  end
135
139
 
140
+ it "model should be Comments" do
141
+ @config[:resource].should == Comments
142
+ end
143
+
136
144
  it "read_only should be correct" do
137
145
  @config[:read_only].should == [:created_at]
138
146
  end
@@ -15,6 +15,10 @@ describe "Sources" do
15
15
  it "model should be Source" do
16
16
  @config[:model].should == Source
17
17
  end
18
+
19
+ it "resource should be Sources" do
20
+ @config[:resource].should == Sources
21
+ end
18
22
 
19
23
  it "read_only should be empty" do
20
24
  @config[:read_only].should == []
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-sinatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David James
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-11 00:00:00 -04:00
12
+ date: 2009-10-14 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency