sinatra_resource 0.1.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.
Files changed (75) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/LICENSE +20 -0
  4. data/README.mdown +28 -0
  5. data/Rakefile +34 -0
  6. data/VERSION +1 -0
  7. data/examples/datacatalog/Rakefile +23 -0
  8. data/examples/datacatalog/app.rb +15 -0
  9. data/examples/datacatalog/config/config.rb +66 -0
  10. data/examples/datacatalog/config/config.yml +11 -0
  11. data/examples/datacatalog/config.ru +6 -0
  12. data/examples/datacatalog/lib/base.rb +9 -0
  13. data/examples/datacatalog/lib/resource.rb +73 -0
  14. data/examples/datacatalog/lib/roles.rb +15 -0
  15. data/examples/datacatalog/models/categorization.rb +31 -0
  16. data/examples/datacatalog/models/category.rb +28 -0
  17. data/examples/datacatalog/models/source.rb +33 -0
  18. data/examples/datacatalog/models/user.rb +51 -0
  19. data/examples/datacatalog/resources/categories.rb +32 -0
  20. data/examples/datacatalog/resources/sources.rb +35 -0
  21. data/examples/datacatalog/resources/users.rb +26 -0
  22. data/examples/datacatalog/tasks/db.rake +29 -0
  23. data/examples/datacatalog/tasks/test.rake +16 -0
  24. data/examples/datacatalog/test/helpers/assertions/assert_include.rb +17 -0
  25. data/examples/datacatalog/test/helpers/assertions/assert_not_include.rb +17 -0
  26. data/examples/datacatalog/test/helpers/lib/model_factories.rb +49 -0
  27. data/examples/datacatalog/test/helpers/lib/model_helpers.rb +30 -0
  28. data/examples/datacatalog/test/helpers/lib/request_helpers.rb +53 -0
  29. data/examples/datacatalog/test/helpers/model_test_helper.rb +5 -0
  30. data/examples/datacatalog/test/helpers/resource_test_helper.rb +5 -0
  31. data/examples/datacatalog/test/helpers/shared/api_keys.rb +48 -0
  32. data/examples/datacatalog/test/helpers/shared/common_body_responses.rb +15 -0
  33. data/examples/datacatalog/test/helpers/shared/status_codes.rb +61 -0
  34. data/examples/datacatalog/test/helpers/test_cases/model_test_case.rb +6 -0
  35. data/examples/datacatalog/test/helpers/test_cases/resource_test_case.rb +36 -0
  36. data/examples/datacatalog/test/helpers/test_helper.rb +36 -0
  37. data/examples/datacatalog/test/models/categorization_test.rb +40 -0
  38. data/examples/datacatalog/test/models/category_test.rb +35 -0
  39. data/examples/datacatalog/test/models/source_test.rb +37 -0
  40. data/examples/datacatalog/test/models/user_test.rb +77 -0
  41. data/examples/datacatalog/test/resources/categories/categories_delete_test.rb +112 -0
  42. data/examples/datacatalog/test/resources/categories/categories_get_many_test.rb +58 -0
  43. data/examples/datacatalog/test/resources/categories/categories_get_one_test.rb +75 -0
  44. data/examples/datacatalog/test/resources/categories/categories_post_test.rb +135 -0
  45. data/examples/datacatalog/test/resources/categories/categories_put_test.rb +140 -0
  46. data/examples/datacatalog/test/resources/sources/sources_delete_test.rb +112 -0
  47. data/examples/datacatalog/test/resources/sources/sources_get_many_test.rb +58 -0
  48. data/examples/datacatalog/test/resources/sources/sources_get_one_test.rb +74 -0
  49. data/examples/datacatalog/test/resources/sources/sources_post_test.rb +184 -0
  50. data/examples/datacatalog/test/resources/sources/sources_put_test.rb +227 -0
  51. data/examples/datacatalog/test/resources/users/users_delete_test.rb +134 -0
  52. data/examples/datacatalog/test/resources/users/users_get_many_test.rb +111 -0
  53. data/examples/datacatalog/test/resources/users/users_get_one_test.rb +75 -0
  54. data/examples/datacatalog/test/resources/users/users_post_test.rb +142 -0
  55. data/examples/datacatalog/test/resources/users/users_put_test.rb +171 -0
  56. data/lib/builder/helpers.rb +319 -0
  57. data/lib/builder/mongo_helpers.rb +70 -0
  58. data/lib/builder.rb +84 -0
  59. data/lib/exceptions.rb +10 -0
  60. data/lib/resource.rb +171 -0
  61. data/lib/roles.rb +163 -0
  62. data/lib/sinatra_resource.rb +6 -0
  63. data/notes/keywords.mdown +1 -0
  64. data/notes/permissions.mdown +181 -0
  65. data/notes/questions.mdown +18 -0
  66. data/notes/see_also.mdown +3 -0
  67. data/notes/synonyms.mdown +7 -0
  68. data/notes/to_do.mdown +7 -0
  69. data/notes/uniform_interface.mdown +22 -0
  70. data/sinatra_resource.gemspec +183 -0
  71. data/spec/sinatra_resource_spec.rb +7 -0
  72. data/spec/spec_helper.rb +9 -0
  73. data/tasks/spec.rake +13 -0
  74. data/tasks/yard.rake +13 -0
  75. metadata +253 -0
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../helpers/resource_test_helper')
2
+
3
+ class UsersGetOneResourceTest < ResourceTestCase
4
+
5
+ def app; DataCatalog::Users end
6
+
7
+ before do
8
+ @user = create_user
9
+ end
10
+
11
+ after do
12
+ @user.destroy
13
+ end
14
+
15
+ context "get /:id" do
16
+ context "anonymous" do
17
+ before do
18
+ get "/#{@user.id}"
19
+ end
20
+
21
+ use "return 401 because the API key is missing"
22
+ end
23
+
24
+ context "incorrect API key" do
25
+ before do
26
+ get "/#{@user.id}", :api_key => BAD_API_KEY
27
+ end
28
+
29
+ use "return 401 because the API key is invalid"
30
+ end
31
+ end
32
+
33
+ %w(basic curator admin).each do |role|
34
+ context "#{role} : get /:fake_id" do
35
+ before do
36
+ get "/#{FAKE_ID}", :api_key => api_key_for(role)
37
+ end
38
+
39
+ use "return 404 Not Found"
40
+ use "return an empty response body"
41
+ end
42
+ end
43
+
44
+ %w(basic curator).each do |role|
45
+ context "#{role} : get /:id" do
46
+ before do
47
+ get "/#{@user.id}", :api_key => api_key_for(role)
48
+ end
49
+
50
+ use "return 200 Ok"
51
+ doc_properties %w(name id created_at updated_at)
52
+ end
53
+ end
54
+
55
+ context "owner : get /:id" do
56
+ before do
57
+ get "/#{@user.id}", :api_key => @user._api_key
58
+ end
59
+
60
+ use "return 200 Ok"
61
+ doc_properties %w(name email role _api_key id created_at updated_at)
62
+ end
63
+
64
+ %w(admin).each do |role|
65
+ context "#{role} : get /:id" do
66
+ before do
67
+ get "/#{@user.id}", :api_key => api_key_for(role)
68
+ end
69
+
70
+ use "return 200 Ok"
71
+ doc_properties %w(name email role _api_key id created_at updated_at)
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,142 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../helpers/resource_test_helper')
2
+
3
+ class UsersPostResourceTest < ResourceTestCase
4
+
5
+ include DataCatalog
6
+
7
+ def app; Users end
8
+
9
+ before do
10
+ @user_count = User.all.length
11
+ @valid_params = {
12
+ :name => "New User",
13
+ :role => "basic"
14
+ }
15
+ @extra_admin_params = {
16
+ :role => "basic",
17
+ :_api_key => "222200004444"
18
+ }
19
+ end
20
+
21
+ shared "no new users" do
22
+ test "should not change number of user documents in database" do
23
+ assert_equal @user_count, User.all.length
24
+ end
25
+ end
26
+
27
+ shared "one new user" do
28
+ test "should add one user document to database" do
29
+ assert_equal @user_count + 1, User.all.length
30
+ end
31
+ end
32
+
33
+ shared "correct Location header" do
34
+ test "should set Location header correctly" do
35
+ base_uri = Config.environment_config["base_uri"]
36
+ path = %(/users/#{parsed_response_body["id"]})
37
+ expected = URI.join(base_uri, path).to_s
38
+ assert_equal expected, last_response.headers['Location']
39
+ end
40
+ end
41
+
42
+ context "post /" do
43
+ context "anonymous" do
44
+ before do
45
+ post "/", @valid_params
46
+ end
47
+
48
+ use "return 401 because the API key is missing"
49
+ use "no new users"
50
+ end
51
+
52
+ context "incorrect API key" do
53
+ before do
54
+ post "/", @valid_params.merge(:api_key => BAD_API_KEY)
55
+ end
56
+
57
+ use "return 401 because the API key is invalid"
58
+ use "no new users"
59
+ end
60
+ end
61
+
62
+ %w(basic curator).each do |role|
63
+ [:name, :role].each do |missing|
64
+ context "#{role} : post / but missing #{missing}" do
65
+ before do
66
+ post "/", valid_params_for(role).delete_if { |k, v| k == missing }
67
+ end
68
+
69
+ use "return 401 Unauthorized"
70
+ use "no new users"
71
+ end
72
+ end
73
+
74
+ [:role, :_api_key, :id, :created_at, :updated_at].each do |invalid|
75
+ context "#{role} : post / but with #{invalid}" do
76
+ before do
77
+ post "/", valid_params_for(role).merge(invalid => 9)
78
+ end
79
+
80
+ use "return 401 Unauthorized"
81
+ use "no new users"
82
+ end
83
+ end
84
+
85
+ context "#{role} : post / with valid params" do
86
+ before do
87
+ post "/", valid_params_for(role)
88
+ end
89
+
90
+ use "return 401 Unauthorized"
91
+ use "no new users"
92
+ end
93
+ end
94
+
95
+ %w(admin).each do |role|
96
+ [:name, :role].each do |missing|
97
+ context "#{role} : post / but missing #{missing}" do
98
+ before do
99
+ post "/", valid_params_for(role).
100
+ merge(@extra_admin_params).delete_if { |k, v| k == missing }
101
+ end
102
+
103
+ use "return 400 Bad Request"
104
+ use "no new users"
105
+ missing_param missing
106
+ end
107
+ end
108
+
109
+ [:id, :created_at, :updated_at].each do |invalid|
110
+ context "#{role} : post / but with #{invalid}" do
111
+ before do
112
+ post "/", valid_params_for(role).
113
+ merge(@extra_admin_params).merge(invalid => 9)
114
+ end
115
+
116
+ use "return 400 Bad Request"
117
+ use "no new users"
118
+ invalid_param invalid
119
+ end
120
+ end
121
+
122
+ context "#{role} : post / with valid params" do
123
+ before do
124
+ post "/", valid_params_for(role).merge(@extra_admin_params)
125
+ end
126
+
127
+ use "return 201 Created"
128
+ use "correct Location header"
129
+ use "one new user"
130
+ doc_properties %w(name email role _api_key id created_at updated_at)
131
+
132
+ test "should set all fields in database" do
133
+ user = User.find_by_id(parsed_response_body["id"])
134
+ raise "Cannot find user" unless user
135
+ @valid_params.merge(@extra_admin_params).each_pair do |key, value|
136
+ assert_equal value, user[key]
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ end
@@ -0,0 +1,171 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../helpers/resource_test_helper')
2
+
3
+ class UsersPutResourceTest < ResourceTestCase
4
+
5
+ include DataCatalog
6
+
7
+ def app; Users end
8
+
9
+ before do
10
+ @user = create_user
11
+ @user_copy = @user.dup
12
+ @valid_params = {
13
+ :name => "Changed User",
14
+ :role => "curator"
15
+ }
16
+ @extra_admin_params = {
17
+ :_api_key => "222200004444"
18
+ }
19
+ end
20
+
21
+ after do
22
+ @user.destroy
23
+ end
24
+
25
+ shared "user unchanged" do
26
+ test "should not change user in database" do
27
+ assert_equal @user_copy, User.find_by_id(@user.id)
28
+ end
29
+ end
30
+
31
+ context "put /:id" do
32
+ context "anonymous" do
33
+ before do
34
+ put "/#{@user.id}", @valid_params
35
+ end
36
+
37
+ use "return 401 because the API key is missing"
38
+ use "user unchanged"
39
+ end
40
+
41
+ context "incorrect API key" do
42
+ before do
43
+ put "/#{@user.id}", @valid_params.merge(:api_key => BAD_API_KEY)
44
+ end
45
+
46
+ use "return 401 because the API key is invalid"
47
+ use "user unchanged"
48
+ end
49
+ end
50
+
51
+ %w(basic curator).each do |role|
52
+ [:created_at, :updated_at].each do |invalid|
53
+ context "#{role} : put / but with #{invalid}" do
54
+ before do
55
+ put "/#{@user.id}", valid_params_for(role).
56
+ merge(@extra_admin_params).merge(invalid => 9)
57
+ end
58
+
59
+ use "return 401 Unauthorized"
60
+ use "user unchanged"
61
+ end
62
+ end
63
+
64
+ [:name, :role].each do |erase|
65
+ context "#{role} : put / but blanking out #{erase}" do
66
+ before do
67
+ put "/#{@user.id}", valid_params_for(role).
68
+ merge(@extra_admin_params).merge(erase => "")
69
+ end
70
+
71
+ use "return 401 Unauthorized"
72
+ use "user unchanged"
73
+ end
74
+ end
75
+
76
+ [:name, :role].each do |missing|
77
+ context "#{role} : put /:id without #{missing}" do
78
+ before do
79
+ put "/#{@user.id}", valid_params_for(role).
80
+ merge(@extra_admin_params).delete_if { |k, v| k == missing }
81
+ end
82
+
83
+ use "return 401 Unauthorized"
84
+ use "user unchanged"
85
+ end
86
+ end
87
+
88
+ context "#{role} : put /:id with valid params" do
89
+ before do
90
+ put "/#{@user.id}", valid_params_for(role).merge(@extra_admin_params)
91
+ end
92
+
93
+ use "return 401 Unauthorized"
94
+ use "user unchanged"
95
+ end
96
+ end
97
+
98
+ %w(admin).each do |role|
99
+ [:created_at, :updated_at].each do |invalid|
100
+ context "#{role} : put / but with #{invalid}" do
101
+ before do
102
+ put "/#{@user.id}", valid_params_for(role).
103
+ merge(@extra_admin_params).merge(invalid => 9)
104
+ end
105
+
106
+ use "return 400 Bad Request"
107
+ use "user unchanged"
108
+ invalid_param invalid
109
+ end
110
+ end
111
+
112
+ [:name, :role].each do |erase|
113
+ context "#{role} : put / but blanking out #{erase}" do
114
+ before do
115
+ put "/#{@user.id}", valid_params_for(role).
116
+ merge(@extra_admin_params).merge(erase => "")
117
+ end
118
+
119
+ use "return 400 Bad Request"
120
+ use "user unchanged"
121
+ missing_param erase
122
+ end
123
+ end
124
+
125
+ context "#{role} : put /:id with no parameters" do
126
+ before do
127
+ put "/#{@user.id}", :api_key => api_key_for(role)
128
+ end
129
+
130
+ use "return 400 because no parameters were given"
131
+ use "user unchanged"
132
+ end
133
+
134
+ [:name, :role].each do |missing|
135
+ context "#{role} : put /:id without #{missing}" do
136
+ before do
137
+ put "/#{@user.id}", valid_params_for(role).
138
+ merge(@extra_admin_params).delete_if { |k, v| k == missing }
139
+ end
140
+
141
+ use "return 200 Ok"
142
+ doc_properties %w(name email role _api_key id created_at updated_at)
143
+
144
+ test "should change correct fields in database" do
145
+ user = User.find_by_id(@user.id)
146
+ @valid_params.merge(@extra_admin_params).each_pair do |key, value|
147
+ assert_equal(value, user[key]) if key != missing
148
+ end
149
+ assert_equal @user_copy[missing], user[missing]
150
+ end
151
+ end
152
+ end
153
+
154
+ context "#{role} : put /:id with valid params" do
155
+ before do
156
+ put "/#{@user.id}", valid_params_for(role).merge(@extra_admin_params)
157
+ end
158
+
159
+ use "return 200 Ok"
160
+ doc_properties %w(name email role _api_key id created_at updated_at)
161
+
162
+ test "should change all fields in database" do
163
+ user = User.find_by_id(@user.id)
164
+ @valid_params.merge(@extra_admin_params).each_pair do |key, value|
165
+ assert_equal value, user[key]
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ end
@@ -0,0 +1,319 @@
1
+ module SinatraResource
2
+
3
+ class Builder
4
+
5
+ module Helpers
6
+
7
+ # Build a resource, based on +document+, appropriate for +role+.
8
+ #
9
+ # @param [Symbol] role
10
+ # a role (such as :anonymous, :basic, or :admin)
11
+ #
12
+ # @param [MongoMapper::Document] document
13
+ #
14
+ # @return [Hash<String => Object>]
15
+ def build_resource(role, document)
16
+ resource = {}
17
+ config[:properties].each_pair do |property, hash|
18
+ if authorized?(:read, role, property)
19
+ resource[property.to_s] = value(property, document, hash)
20
+ end
21
+ end
22
+ resource
23
+ end
24
+
25
+ # Builds a list of resources, based on +documents+, using the
26
+ # appropriate role for each document. (Delegates to +lookup_role+.)
27
+ #
28
+ # @param [Array<MongoMapper::Document>] documents
29
+ #
30
+ # @param [String] api_key
31
+ #
32
+ # @return [Array<Hash<String => Object>>]
33
+ def build_resources(documents)
34
+ documents.map do |document|
35
+ build_resource(lookup_role(document), document)
36
+ end
37
+ end
38
+
39
+ # Halt unless the current params are ok for +action+ and +role+.
40
+ #
41
+ # @param [Symbol] action
42
+ # :read, :create, :update, or :delete
43
+ #
44
+ # @param [Symbol] role
45
+ # a role (such as :anonymous, :basic, or :admin)
46
+ #
47
+ # @return [undefined]
48
+ def check_params(action, role)
49
+ params_check_action(action)
50
+ params_check_action_and_role(action, role)
51
+ end
52
+
53
+ # Halt unless the current role has permission to carry out +action+
54
+ #
55
+ # @param [Symbol] action
56
+ # :read, :create, :update, or :delete
57
+ #
58
+ # @param [Symbol] role
59
+ # a role (such as :anonymous, :basic, or :admin)
60
+ #
61
+ # @return [undefined]
62
+ def check_permission(action, role)
63
+ before_authorization(action, role)
64
+ unless authorized?(action, role)
65
+ error 401, convert(body_for(:unauthorized))
66
+ end
67
+ end
68
+
69
+ # Convert +object+ to desired format.
70
+ #
71
+ # For example, an application might want to convert +object+ to JSON or
72
+ # XML.
73
+ #
74
+ # Applications must override this method.
75
+ #
76
+ # @param [Object] object
77
+ #
78
+ # @return [String]
79
+ def convert
80
+ raise NotImplementedError
81
+ end
82
+
83
+ # Display +object+ as appropriate for +action+.
84
+ #
85
+ # @param [Object] object
86
+ #
87
+ # @return [String]
88
+ def display(action, object)
89
+ case action
90
+ when :read
91
+ when :create
92
+ response.status = 201
93
+ path = config[:path] + %(/#{object["id"]})
94
+ response.headers['Location'] = full_uri(path)
95
+ when :update
96
+ when :delete
97
+ response.status = 204
98
+ end
99
+ convert(object)
100
+ end
101
+
102
+ # Convert a path to a full URI.
103
+ #
104
+ # Applications must override this method.
105
+ #
106
+ # @param [String] path
107
+ #
108
+ # @return [String]
109
+ def full_uri(path)
110
+ raise NotImplementedError
111
+ end
112
+
113
+ # Get role, using +id+ if specified. Delegates to +lookup_role+.
114
+ #
115
+ # When +id+ is present, it can help determine 'relative' roles such
116
+ # as 'ownership' of the current user of a particular document.
117
+ #
118
+ # @param [String, nil] id
119
+ #
120
+ # @return [Symbol]
121
+ def get_role(id=nil)
122
+ lookup_role(id ? config[:model].find_by_id(id) : nil)
123
+ end
124
+
125
+ # Return the minimum role required for +action+, and, if specified,
126
+ # +property+.
127
+ #
128
+ # @param [Symbol] action
129
+ # :read, :create, :update, or :delete
130
+ #
131
+ # @return [Symbol]
132
+ # a role (such as :anonymous, :basic, or :admin)
133
+ def minimum_role(action, property=nil)
134
+ if property.nil?
135
+ config[:permission][to_read_or_modify(action)]
136
+ else
137
+ config[:properties][property][to_r_or_w(action)]
138
+ end || :anonymous
139
+ end
140
+
141
+ protected
142
+
143
+ # Is +role+ authorized for +action+, and, if specified, +property+?
144
+ #
145
+ # @param [Symbol] role
146
+ # a role (such as :anonymous, :basic, or :admin)
147
+ #
148
+ # @param [Symbol] action
149
+ # :read, :create, :update, or :delete
150
+ #
151
+ # @param [Symbol] property
152
+ # a property of a resource
153
+ #
154
+ # @return [Boolean]
155
+ def authorized?(action, role, property=nil)
156
+ klass = config[:roles]
157
+ klass.validate_role(role)
158
+ klass.satisfies?(role, minimum_role(action, property))
159
+ end
160
+
161
+ # Application-level hook that runs as part of +check_permission+,
162
+ # before +authorized?(action, role)+ is called.
163
+ #
164
+ # For example, an application might want to throw custom errors
165
+ # in certain situations before +authorized?+ runs.
166
+ #
167
+ # Applications must override this method.
168
+ #
169
+ # @param [Symbol] action
170
+ # :read, :create, :update, or :delete
171
+ #
172
+ # @param [Symbol] role
173
+ # a role (such as :anonymous, :basic, or :admin)
174
+ #
175
+ # @return [String]
176
+ def before_authorization(action, role)
177
+ raise NotImplementedError
178
+ end
179
+
180
+ # Default body message for a +situation+
181
+ #
182
+ # @param [Symbol] situation
183
+ #
184
+ # @param [Object] object
185
+ #
186
+ # @return [String]
187
+ def body_for(situation, object=nil)
188
+ case situation
189
+ when :errors
190
+ { "errors" => object }
191
+ when :internal_server_error
192
+ ""
193
+ when :invalid_document
194
+ { "errors" => object.errors.errors }
195
+ when :invalid_params
196
+ { "errors" => { "invalid_params" => object } }
197
+ when :no_params
198
+ { "errors" => "no_params" }
199
+ when :non_empty_params
200
+ { "errors" => "non_empty_params" }
201
+ when :not_found
202
+ ""
203
+ when :unauthorized
204
+ ""
205
+ end
206
+ end
207
+
208
+ # Lookup the rol, using +document+ if specified.
209
+ #
210
+ # Applications must override this method.
211
+ #
212
+ # @param [MongoMapper::Document, nil] document
213
+ #
214
+ # @return [Symbol]
215
+ def lookup_role(document=nil)
216
+ raise NotImplementedError
217
+ end
218
+
219
+ # Are the params suitable for +action+? Raise 400 Bad Request if not.
220
+ #
221
+ # @param [Symbol] action
222
+ # :read, :create, :update, or :delete
223
+ #
224
+ # @return [undefined]
225
+ def params_check_action(action)
226
+ case action
227
+ when :read
228
+ unless params.empty?
229
+ error 400, convert(body_for(:non_empty_params))
230
+ end
231
+ when :create
232
+ # No need to complain. If there are problems,
233
+ # params_check_action_and_role will catch them.
234
+ when :update
235
+ if params.empty?
236
+ error 400, convert(body_for(:no_params))
237
+ end
238
+ when :delete
239
+ unless params.empty?
240
+ error 400, convert(body_for(:non_empty_params))
241
+ end
242
+ end
243
+ end
244
+
245
+ # Checks each parameter to make sure it is authorized for +action+ and
246
+ # +role+. Raises a 400 Bad Request if not authorized.
247
+ #
248
+ # @param [Symbol] action
249
+ # :read, :create, :update, or :delete
250
+ #
251
+ # @param [Symbol] role
252
+ # a role (such as :anonymous, :basic, or :admin)
253
+ #
254
+ # @return [undefined]
255
+ def params_check_action_and_role(action, role)
256
+ invalid = []
257
+ params.each_pair do |property, value|
258
+ invalid << property if !authorized?(action, role, property.intern)
259
+ end
260
+ unless invalid.empty?
261
+ error 400, convert(body_for(:invalid_params, invalid))
262
+ end
263
+ end
264
+
265
+ # Converts +action+ to :r or :w (i.e. read or write).
266
+ #
267
+ # @param [Symbol] action
268
+ # :read, :create, or :update
269
+ #
270
+ # @return [Symbol]
271
+ # :r or :w
272
+ def to_r_or_w(action)
273
+ case action
274
+ when :read then :r
275
+ when :create then :w
276
+ when :update then :w
277
+ else raise "Unexpected action : #{action.inspect}"
278
+ end
279
+ end
280
+
281
+ # Converts +action+ to (:read or :modify).
282
+ #
283
+ # @param [Symbol] action
284
+ # :read, :create, :update, or :delete
285
+ #
286
+ # @return [Symbol]
287
+ # :read or :modify
288
+ def to_read_or_modify(action)
289
+ case action
290
+ when :read then :read
291
+ when :create then :modify
292
+ when :update then :modify
293
+ when :delete then :modify
294
+ else raise "Unexpected action : #{action.inspect}"
295
+ end
296
+ end
297
+
298
+ # Lookup +attribute+ in +document+
299
+ #
300
+ # @param [Symbol] attribute
301
+ # an attribute of +document+
302
+ #
303
+ # @param [MongoMapper::Document] document
304
+ #
305
+ # @return [undefined]
306
+ def value(attribute, document, property_hash)
307
+ proc = property_hash[:read_proc]
308
+ if proc
309
+ proc.call(document)
310
+ else
311
+ document[attribute == :id ? :_id : attribute]
312
+ end
313
+ end
314
+
315
+ end
316
+
317
+ end
318
+
319
+ end