trust 0.5.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 (106) hide show
  1. data/MIT-LICENSE +23 -0
  2. data/README.md +244 -0
  3. data/Rakefile +37 -0
  4. data/lib/tasks/trust_tasks.rake +42 -0
  5. data/lib/trust/active_record.rb +65 -0
  6. data/lib/trust/authorization.rb +85 -0
  7. data/lib/trust/controller/properties.rb +134 -0
  8. data/lib/trust/controller/resource.rb +306 -0
  9. data/lib/trust/controller.rb +197 -0
  10. data/lib/trust/exceptions.rb +45 -0
  11. data/lib/trust/inheritable_attribute.rb +91 -0
  12. data/lib/trust/permissions.rb +268 -0
  13. data/lib/trust/test_helper.rb +56 -0
  14. data/lib/trust/version.rb +27 -0
  15. data/lib/trust.rb +39 -0
  16. data/test/dummy/README.rdoc +261 -0
  17. data/test/dummy/Rakefile +7 -0
  18. data/test/dummy/app/assets/javascripts/accounts.js +2 -0
  19. data/test/dummy/app/assets/javascripts/application.js +15 -0
  20. data/test/dummy/app/assets/javascripts/clients.js +2 -0
  21. data/test/dummy/app/assets/javascripts/users.js +2 -0
  22. data/test/dummy/app/assets/stylesheets/accounts.css +4 -0
  23. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  24. data/test/dummy/app/assets/stylesheets/clients.css +4 -0
  25. data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
  26. data/test/dummy/app/assets/stylesheets/users.css +4 -0
  27. data/test/dummy/app/controllers/accounts_controller.rb +100 -0
  28. data/test/dummy/app/controllers/application_controller.rb +31 -0
  29. data/test/dummy/app/controllers/clients_controller.rb +107 -0
  30. data/test/dummy/app/controllers/savings_accounts_controller.rb +27 -0
  31. data/test/dummy/app/controllers/settlements_controller.rb +26 -0
  32. data/test/dummy/app/controllers/users_controller.rb +107 -0
  33. data/test/dummy/app/helpers/accounts_helper.rb +26 -0
  34. data/test/dummy/app/helpers/application_helper.rb +26 -0
  35. data/test/dummy/app/helpers/clients_helper.rb +26 -0
  36. data/test/dummy/app/helpers/users_helper.rb +26 -0
  37. data/test/dummy/app/models/account/credit.rb +26 -0
  38. data/test/dummy/app/models/account.rb +35 -0
  39. data/test/dummy/app/models/client.rb +35 -0
  40. data/test/dummy/app/models/permissions.rb +68 -0
  41. data/test/dummy/app/models/savings_account.rb +26 -0
  42. data/test/dummy/app/models/user.rb +40 -0
  43. data/test/dummy/app/views/accounts/_form.html.erb +46 -0
  44. data/test/dummy/app/views/accounts/edit.html.erb +31 -0
  45. data/test/dummy/app/views/accounts/index.html.erb +48 -0
  46. data/test/dummy/app/views/accounts/new.html.erb +30 -0
  47. data/test/dummy/app/views/accounts/show.html.erb +35 -0
  48. data/test/dummy/app/views/clients/_form.html.erb +46 -0
  49. data/test/dummy/app/views/clients/edit.html.erb +31 -0
  50. data/test/dummy/app/views/clients/index.html.erb +48 -0
  51. data/test/dummy/app/views/clients/new.html.erb +30 -0
  52. data/test/dummy/app/views/clients/show.html.erb +35 -0
  53. data/test/dummy/app/views/layouts/application.html.erb +39 -0
  54. data/test/dummy/app/views/users/_form.html.erb +46 -0
  55. data/test/dummy/app/views/users/edit.html.erb +31 -0
  56. data/test/dummy/app/views/users/index.html.erb +48 -0
  57. data/test/dummy/app/views/users/new.html.erb +30 -0
  58. data/test/dummy/app/views/users/show.html.erb +35 -0
  59. data/test/dummy/config/application.rb +56 -0
  60. data/test/dummy/config/boot.rb +10 -0
  61. data/test/dummy/config/database.yml +25 -0
  62. data/test/dummy/config/environment.rb +5 -0
  63. data/test/dummy/config/environments/development.rb +37 -0
  64. data/test/dummy/config/environments/production.rb +67 -0
  65. data/test/dummy/config/environments/test.rb +37 -0
  66. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  67. data/test/dummy/config/initializers/inflections.rb +15 -0
  68. data/test/dummy/config/initializers/mime_types.rb +5 -0
  69. data/test/dummy/config/initializers/secret_token.rb +7 -0
  70. data/test/dummy/config/initializers/session_store.rb +8 -0
  71. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  72. data/test/dummy/config/locales/en.yml +5 -0
  73. data/test/dummy/config/routes.rb +38 -0
  74. data/test/dummy/config.ru +4 -0
  75. data/test/dummy/db/migrate/20120522115011_create_accounts.rb +36 -0
  76. data/test/dummy/db/migrate/20120522130322_create_users.rb +33 -0
  77. data/test/dummy/db/migrate/20120523144144_create_clients.rb +34 -0
  78. data/test/dummy/db/schema.rb +38 -0
  79. data/test/dummy/public/404.html +26 -0
  80. data/test/dummy/public/422.html +26 -0
  81. data/test/dummy/public/500.html +25 -0
  82. data/test/dummy/public/favicon.ico +0 -0
  83. data/test/dummy/script/rails +6 -0
  84. data/test/dummy/test/fixtures/accounts.yml +7 -0
  85. data/test/dummy/test/fixtures/clients.yml +7 -0
  86. data/test/dummy/test/fixtures/users.yml +7 -0
  87. data/test/dummy/test/functional/accounts_controller_test.rb +123 -0
  88. data/test/dummy/test/functional/clients_controller_test.rb +74 -0
  89. data/test/dummy/test/functional/users_controller_test.rb +74 -0
  90. data/test/dummy/test/unit/account_test.rb +31 -0
  91. data/test/dummy/test/unit/client_test.rb +31 -0
  92. data/test/dummy/test/unit/helpers/accounts_helper_test.rb +28 -0
  93. data/test/dummy/test/unit/helpers/clients_helper_test.rb +28 -0
  94. data/test/dummy/test/unit/helpers/users_helper_test.rb +28 -0
  95. data/test/dummy/test/unit/permissions_test.rb +171 -0
  96. data/test/dummy/test/unit/user_test.rb +31 -0
  97. data/test/test_helper.rb +45 -0
  98. data/test/trust_test.rb +31 -0
  99. data/test/unit/trust/active_record_test.rb +56 -0
  100. data/test/unit/trust/authorization_test.rb +108 -0
  101. data/test/unit/trust/controller/properties_test.rb +132 -0
  102. data/test/unit/trust/controller/resource_test.rb +251 -0
  103. data/test/unit/trust/controller_test.rb +160 -0
  104. data/test/unit/trust/inheritable_attribute_test.rb +65 -0
  105. data/test/unit/trust/permissions_test.rb +258 -0
  106. metadata +280 -0
@@ -0,0 +1,306 @@
1
+ # Copyright (c) 2012 Bingo Entreprenøren AS
2
+ # Copyright (c) 2012 Teknobingo Scandinavia AS
3
+ # Copyright (c) 2012 Knut I. Stenmark
4
+ # Copyright (c) 2012 Patrick Hanevold
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ module Trust
26
+ module Controller
27
+ class Resource
28
+ # = Trust::Controller::Resource
29
+ # Collects information about the current resource and relations.
30
+ # Handles the loading of the resource and its possible parent, i.e. setting the relevant instance variables
31
+ # It assumes the name of the resource is built on the controllers name, but this can be overridden in your
32
+ # controller by setting the +model+
33
+ #
34
+ # Examples:
35
+ #
36
+ # # controller name AccountsController
37
+ # resource.instance # => @account
38
+ #
39
+ # # controller name Customer::AccountsController
40
+ # resource.instance # => @customer_account
41
+ #
42
+
43
+ delegate :logger, :to => Rails
44
+ attr_reader :properties, :params, :action
45
+ attr_reader :info, :parent_info, :relation
46
+
47
+ def initialize(controller, properties, action_name, params, request) # nodoc
48
+ @action = action_name.to_sym
49
+
50
+ @controller, @properties, @params = controller, properties, params
51
+ @info = extract_resource_info(properties.model, params)
52
+ if properties.has_associations?
53
+ @parent_info = extract_parent_info(properties.associations, params, request)
54
+ end
55
+ @relation = @info.relation(@parent_info)
56
+ end
57
+
58
+ # Returns the instance variable in the controller
59
+ def instance
60
+ @controller.instance_variable_get(:"@#{instance_name}")
61
+ end
62
+
63
+ # Sets the instance variable
64
+ # Normally set by +load+
65
+ # You can access this method from the resource object.
66
+ #
67
+ # ==== Example
68
+ #
69
+ # resource.instance = Account.find_by_number(123456)
70
+ def instance=(instance)
71
+ @controller.instance_variable_set(:"@#{instance_name}", instance)
72
+ end
73
+
74
+ # Returns the parameters for the instance
75
+ #
76
+ # ==== Example
77
+ #
78
+ # # in AccountsController
79
+ # resource.instance_params # same as params[:account]
80
+ def instance_params
81
+ info.params
82
+ end
83
+
84
+ # Returns the parents instance variable when you use +belongs_to+ for nested routes
85
+ def parent
86
+ @controller.instance_variable_get(:"@#{parent_name}")
87
+ end
88
+
89
+ # Sets the parent instance variable
90
+ def parent=(instance)
91
+ @controller.instance_variable_set(:"@#{parent_name}", instance)
92
+ end
93
+
94
+ # Returns the cinstance variable for ollection
95
+ def instances
96
+ @controller.instance_variable_get(:"@#{plural_instance_name}")
97
+ end
98
+
99
+ # Sets the instance variable for collection
100
+ # You may want to set this variable in your index action, we do not yet support loading of collections
101
+ def instances=(instances)
102
+ @controller.instance_variable_set(:"@#{plural_instance_name}", instances)
103
+ end
104
+
105
+ # Returns either the instances or the instance.
106
+ # We have found that this can be useful in some implementation patterns
107
+ def instantiated
108
+ instances || instance
109
+ end
110
+
111
+ # Returns the class for the resource
112
+ def klass
113
+ info.klass
114
+ end
115
+
116
+ # Loads the resource
117
+ # See Trust::Controller::Properties which controls the behavior of this method.
118
+ # It will normally find the instance variable for existing object or initialize them as new.
119
+ # If using nested resources and +belongs_to+ has been declared in the controller it will use the
120
+ # parent relation if found.
121
+ def load
122
+ self.parent = parent_info.object if parent_info
123
+ if properties.new_actions.include?(action)
124
+ # logger.debug "Trust.load: Setting new: class: #{klass} info.params: #{info.params.inspect}"
125
+ self.instance ||= relation.new(info.params)
126
+ @controller.send(:build, action) if @controller.respond_to?(:build)
127
+ elsif properties.member_actions.include?(action)
128
+ # logger.debug "Trust.load: Finding parent: #{parent.inspect}, relation: #{relation.inspect}"
129
+ self.instance ||= relation.find(params[:id])
130
+ @controller.send(:build, action) if @controller.respond_to?(:build)
131
+ else # other outcome would be collection actions
132
+ # logger.debug "Trust.load: Parent is: #{parent.inspect}, collection or unknown action."
133
+ end
134
+ end
135
+
136
+ # Returns the name of the instance for the resource
137
+ # ==== Example
138
+ #
139
+ # # in AccountsController
140
+ # resource.instance_name # => :account
141
+ def instance_name
142
+ info.name
143
+ end
144
+
145
+ # Returns the plural name of the instance for the resource
146
+ # ==== Example
147
+ #
148
+ # # in AccountsController
149
+ # resource.plural_instance_name # => :accounts
150
+ def plural_instance_name
151
+ info.plural_name
152
+ end
153
+
154
+ # Returns the name of the parent resource
155
+ # ==== Example
156
+ #
157
+ # # in AccountsController where belongs_to :customer has been declared
158
+ # resource.parent_name # => :customer
159
+ def parent_name
160
+ parent_info && parent_info.name
161
+ end
162
+
163
+
164
+ private
165
+ def extract_resource_info(model, params) # nodoc
166
+ ResourceInfo.new(model, params)
167
+ end
168
+
169
+ def extract_parent_info(associations, params, request) #nodoc
170
+ ParentInfo.new(associations, params, request)
171
+ end
172
+ end
173
+
174
+ # ResorceInfo resolves information about the resource accessed in action controller
175
+ #
176
+ # Examples in PeopleController (simple case)
177
+ # ===
178
+ # resource.info.klass => Person
179
+ # resource.info.params => {:person => {...}} # fetches the parameters for the resource
180
+ # resource.info.name => :person
181
+ # resource.info.plural_name => :people
182
+ # resource.info.path => 'people' # this is the controller_path
183
+ #
184
+ # Examples in Lottery::AssignmentsController (with name space)
185
+ # ===
186
+ # resource.info.klass => Lottery::Assignment
187
+ # resource.info.params => {:lottery_assignment => {...}}
188
+ # resource.info.name => :lottery_assignment
189
+ # resource.info.plural_name => :lottery_assignments
190
+ # resource.info.path => 'lottery/assignments' # this is the controller_path
191
+ #
192
+ # Examples in ArchiveController (with inheritance)
193
+ # Assumptions on routes:
194
+ # resources :archives
195
+ # resources :secret_acrvives, :controller => :archives
196
+ # resources :public_acrvives, :controller => :archives
197
+ # examples below assumes that the route secret_arcives is being accessed at the moment
198
+ # ===
199
+ # resource.info.klass => Archive
200
+ # resource.info.params => {:secret_archive => {...}}
201
+ # resource.info.name => :archive
202
+ # resource.info.plural_name => :archives
203
+ # resource.info.path => 'archive' # this is the controller_path
204
+ # resource.info.real_class => SecretArchive # Returns the real class which is accessed at the moment
205
+ #
206
+
207
+ class Resource::Info
208
+ attr_reader :klass, :params, :name, :path, :real_class
209
+
210
+ def params
211
+ @data
212
+ end
213
+
214
+ protected
215
+ def self.var_name(klass)
216
+ klass.to_s.underscore.tr('/','_').to_sym
217
+ end
218
+ def var_name(klass)
219
+ self.class.var_name(klass)
220
+ end
221
+ end
222
+
223
+
224
+ class Resource::ResourceInfo < Resource::Info
225
+
226
+ def initialize(model, params)
227
+ @path, params = model, params
228
+ @klass = model.to_s.classify.constantize
229
+ @name = model.to_s.singularize.underscore.gsub('/','_').to_sym
230
+ ptr = @klass.descendants.detect do |c|
231
+ params.key? var_name(c)
232
+ end || @klass
233
+ @real_class = ptr
234
+ @data = params[var_name(ptr)]
235
+ end
236
+
237
+ def plural_name
238
+ @plural_name ||= path.underscore.tr('/','_').to_sym
239
+ end
240
+
241
+ # returns an accessor for association. Tries with full name association first, and if that does not match, tries the demodularized association.
242
+ #
243
+ # Explanation:
244
+ # Assuming
245
+ # resource is instance of Lottery::Package #1 (@lottery_package)
246
+ # association is Lottery::Prizes
247
+ # if association is named lottery_prizes, then that association is returned
248
+ # if association is named prizes, then that association is returned
249
+ #
250
+ def relation(associated_resource)
251
+ if associated_resource && associated_resource.object
252
+ name = associated_resource.as || plural_name
253
+ associated_resource.klass.reflect_on_association(name) ?
254
+ associated_resource.object.send(name) : associated_resource.object.send(klass.to_s.demodulize.underscore.pluralize)
255
+ else
256
+ klass
257
+ end
258
+ end
259
+ end
260
+
261
+ class Resource::ParentInfo < Resource::Info
262
+ attr_reader :object,:as
263
+ def initialize(resources, params, request)
264
+ ptr = resources.detect do |r,as|
265
+ @klass = classify(r)
266
+ @as = as
267
+ ([@klass] + @klass.descendants).detect do |c|
268
+ @name = c.to_s.underscore.tr('/','_').to_sym
269
+ unless @id = request.symbolized_path_parameters["#{@name}_id".to_sym]
270
+ # see if name space handling is necessary
271
+ if c.to_s.include?('::')
272
+ @name = c.to_s.demodulize.underscore.to_sym
273
+ @id = request.symbolized_path_parameters["#{@name}_id".to_sym]
274
+ end
275
+ end
276
+ @id
277
+ end
278
+ @id
279
+ end
280
+ if ptr
281
+ @object = @klass.find(@id)
282
+ else
283
+ @klass = @name = nil
284
+ end
285
+ @data = params[var_name(ptr)]
286
+ end
287
+
288
+ def object?
289
+ !!@object
290
+ end
291
+
292
+ def real_class
293
+ @object && @object.class
294
+ end
295
+ private
296
+ def classify(resource)
297
+ case resource
298
+ when Symbol, String
299
+ resource.to_s.classify.constantize
300
+ else
301
+ resource
302
+ end
303
+ end
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,197 @@
1
+ # Copyright (c) 2012 Bingo Entreprenøren AS
2
+ # Copyright (c) 2012 Teknobingo Scandinavia AS
3
+ # Copyright (c) 2012 Knut I. Stenmark
4
+ # Copyright (c) 2012 Patrick Hanevold
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ module Trust
26
+ module Controller
27
+ autoload :Resource, 'trust/controller/resource'
28
+ autoload :Properties, 'trust/controller/properties'
29
+
30
+ extend ActiveSupport::Concern
31
+
32
+ module ClassMethods
33
+
34
+ # Returns the controller Trust::Controller::Properties.
35
+ # If no properties are instantiated, it will be instantiated
36
+ #
37
+ # == Delegated methods
38
+ #
39
+ # The following methods are delegated to properties. See Trust::Controller::Properties for details
40
+ # * <tt>belongs_to</tt> - define one or more associations to parents
41
+ # * <tt>actions</tt> - acion definitions outside the restful actions
42
+ # * <tt>model</tt> - Redefine the model used in the controller (if it's name does not match the
43
+ # controller_path)
44
+ #
45
+ def properties
46
+ @properties ||= Trust::Controller::Properties.instantiate(self)
47
+ end
48
+
49
+ delegate :belongs_to, :actions, :model, :to => :properties
50
+
51
+ # Enables authorization in controller
52
+ # +trustee+ accepts +:off+ or a hash of +callback+ options such as +:except+ and +:only+
53
+ #
54
+ # +trustee+ automatically calls the class methods: +set_user+, +load_resource+ and +access_control+
55
+ #
56
+ # +trustee+ will raise an Trust::AccessDenied exception if the user is not permitted the action
57
+ #
58
+ # ==== Examples
59
+ #
60
+ # # enable permission check for all restful actions
61
+ # class AccountsController < ApplicationController
62
+ # login_required
63
+ # trustee
64
+ # end
65
+ #
66
+ # # disable all permission check
67
+ # class PasswordController < ApplicationController
68
+ # # assuming login_required and trustee has been in your application controller
69
+ # trustee :off
70
+ # end
71
+ #
72
+ # # enable permission check and loading for only :new and :create action
73
+ # class AccountsController < ApplicationController
74
+ # login_required
75
+ # trustee :only => [:new, :create]
76
+ # end
77
+ #
78
+ # ==== Caching Trust::AccessDenied exception
79
+ # Normally an exception handler is included in the ApplicationController. Example:
80
+ # class ApplicationController < ActionController::Base
81
+ # rescue_from Trust::AccessDenied do |exception|
82
+ # redirect_to root_url, :alert => exception.message
83
+ # end
84
+ # end
85
+
86
+
87
+ def trustee(*args)
88
+ module_eval do
89
+ include TrustInstanceMethods
90
+ set_user *args
91
+ load_resource *args
92
+ access_control *args
93
+ helper_method :can?, :resource
94
+ end
95
+ end
96
+
97
+ # Enable or disable +before_filter+ callback for setting the current user
98
+ # Arguments:
99
+ # :off - switch callback off
100
+ # :only - only include these actions
101
+ # :except - except these actions
102
+ def set_user(*args)
103
+ _filter_setting(:set_user, *args)
104
+ end
105
+ # Enable or disable +before_filter+ callback for setting the loading resource
106
+ # Arguments:
107
+ # :off - switch callback off
108
+ # :only - only include these actions
109
+ # :except - except these actions
110
+ def load_resource(*args)
111
+ _filter_setting(:load_resource, *args)
112
+ end
113
+ # Enable or disable +before_filter+ callback for setting the access control, i.e. verifying permissions
114
+ # for the logged in user
115
+ # Arguments:
116
+ # :off - switch callback off
117
+ # :only - only include these actions
118
+ # :except - except these actions
119
+ def access_control(*args)
120
+ _filter_setting(:access_control, *args)
121
+ end
122
+
123
+ private
124
+ def _filter_setting(method, *args)
125
+ options = args.extract_options!
126
+ skip_before_filter method
127
+ unless args.include? :off
128
+ before_filter method, options
129
+ end
130
+ end
131
+ end
132
+
133
+ module TrustInstanceMethods
134
+ # Returns the controller Trust::Controller::Properties.
135
+ # If no properties are instantiated, it will be instantiated
136
+ #
137
+ # == Delegated methods
138
+ #
139
+ # The following methods are delegated to properties. See Trust::Controller::Properties for details
140
+ # * <tt>belongs_to</tt> - define one or more associations to parents
141
+ # * <tt>actions</tt> - acion definitions outside the restful actions
142
+ # * <tt>model</tt> - Redefine the model used in the controller (if it's name does not match the
143
+ # controller_path)
144
+ #
145
+ def properties
146
+ self.class.properties
147
+ end
148
+
149
+ # Sets the current user. It assumes +current_user+ is defined
150
+ # This method is triggered as a callback on +before_filter+
151
+ # You may override this method.
152
+ #
153
+ # ==== Example
154
+ #
155
+ # def set_user
156
+ # Trust::Authorization.user = Thread[:current_user]
157
+ # end
158
+ def set_user
159
+ Trust::Authorization.user = current_user
160
+ end
161
+
162
+ # Returns the Trust::Controller::Resource resource for the controller.
163
+ # Available as a helper in views
164
+ # See Trust::Controller::Resource for relevant methods
165
+ def resource
166
+ @resource ||= Trust::Controller::Resource.new(self, self.class.properties, action_name, params, request)
167
+ end
168
+
169
+ # Loads the resource which basically means loading the instance and eventual parent defined through +belongs_to+
170
+ # This method is triggered as a callback on +before_filter+
171
+ # See Trust::Controller::Resource for more information
172
+ def load_resource
173
+ resource.load
174
+ end
175
+
176
+ # Performs the actual access_control
177
+ # This method is triggered as a callback on +before_filter+
178
+ def access_control
179
+ Trust::Authorization.authorize!(action_name, resource.instance || resource.klass, resource.parent)
180
+ end
181
+
182
+ # Tests for current users permissions
183
+ # If access control is not sufficient in controller, you may use this method.
184
+ # Also available as a helper in views
185
+ #
186
+ # ==== Examples
187
+ # can? :edit # does the current user have permission to edit the current resource?
188
+ # # If there is a nested resource, the parent is automatically associated
189
+ # can? :edit, @customer # does the current user have permission to edit the given customer?
190
+ # # Parent is also passed on here.
191
+ # can? :edit, @account, @client # is current user allowed to edit the account associated with the client?
192
+ def can?(action_name, subject = resource.instance || resource.klass, parent = resource.parent)
193
+ Trust::Authorization.authorized?(action_name, subject, parent)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright (c) 2012 Bingo Entreprenøren AS
2
+ # Copyright (c) 2012 Teknobingo Scandinavia AS
3
+ # Copyright (c) 2012 Knut I. Stenmark
4
+ # Copyright (c) 2012 Patrick Hanevold
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ module Trust
26
+ class NoBlockError < StandardError; end
27
+ class UnsupportedCondition < StandardError; end
28
+ class RoleAssigmnentMissing < StandardError; end
29
+
30
+ class AccessDenied < StandardError
31
+ attr_reader :action, :subject
32
+ attr_writer :default_message
33
+
34
+ def initialize(message = nil, action = nil, subject = nil)
35
+ @message = message
36
+ @action = action
37
+ @subject = subject
38
+ @default_message = I18n.t(:"unauthorized.default", :default => "You are not authorized to access this page.")
39
+ end
40
+
41
+ def to_s
42
+ @message || @default_message
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,91 @@
1
+ # Copyright (c) 2012 Bingo Entreprenøren AS
2
+ # Copyright (c) 2012 Teknobingo Scandinavia AS
3
+ # Copyright (c) 2012 Knut I. Stenmark
4
+ # Copyright (c) 2012 Patrick Hanevold
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ module Trust
26
+ module InheritableAttribute
27
+
28
+ def self.deep_copy value
29
+ if value.is_a? Hash
30
+ Hash[*value.map{ |k,v| [self.deep_copy(k),self.deep_copy(v)] }.flatten(1)]
31
+ elsif value.is_a? Array
32
+ value.map{ |v| self.deep_copy(v) }
33
+ elsif value.is_a? Symbol
34
+ value
35
+ else
36
+ value.clone
37
+ end
38
+ end
39
+
40
+ extend ActiveSupport::Concern
41
+
42
+ module ClassMethods
43
+ # Creates an inheritable attribute with accessors in the singleton class. Derived classes inherit the
44
+ # attributes. This is especially helpful with arrays or hashes that are extended in the inheritance
45
+ # chain. Note that you have to initialize the inheritable attribute.
46
+ #
47
+ # Example:
48
+ #
49
+ # class Cat
50
+ # inheritable_attr :drinks
51
+ # self.drinks = ["Becks"]
52
+ #
53
+ # class Garfield < Cat
54
+ # self.drinks << "Fireman's 4"
55
+ #
56
+ # and then, later
57
+ #
58
+ # Cat.drinks #=> ["Becks"]
59
+ # Garfield.drinks #=> ["Becks", "Fireman's 4"]
60
+ def inheritable_attr(name, options = {})
61
+ src = <<-end_src
62
+ def #{name}=(v)
63
+ @#{name} = v
64
+ end
65
+
66
+ def #{name}
67
+ return @#{name} unless superclass.respond_to?(:#{name}) and value = superclass.#{name}
68
+ @#{name} ||= ::Trust::InheritableAttribute::deep_copy(value) # only do this once.
69
+ end
70
+ end_src
71
+ instance_eval src, __FILE__, __LINE__
72
+ if !options.key?(:instance_writer) || options[:instance_writer]
73
+ src = <<-end_src
74
+ def #{name}=(v)
75
+ self.class.#{name} = v
76
+ end
77
+ end_src
78
+ class_eval src, __FILE__, __LINE__
79
+ end
80
+ if !options.key?(:instance_reader) || options[:instance_reader]
81
+ src = <<-end_src
82
+ def #{name}
83
+ self.class.#{name}
84
+ end
85
+ end_src
86
+ class_eval src, __FILE__, __LINE__
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end