authorization_next 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.
- data/.gitignore +8 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/authorization.iml +13 -0
- data/.idea/inspectionProfiles/Project_Default.xml +6 -0
- data/.idea/misc.xml +7 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +277 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +2 -0
- data/authorization.gemspec +29 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/authorization_next.rb +172 -0
- data/lib/authorization_next/publishare/exceptions.rb +40 -0
- data/lib/authorization_next/publishare/hardwired_roles.rb +81 -0
- data/lib/authorization_next/publishare/identity.rb +125 -0
- data/lib/authorization_next/publishare/object_roles_table.rb +118 -0
- data/lib/authorization_next/publishare/parser.rb +210 -0
- data/lib/authorization_next/version.rb +3 -0
- metadata +102 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Pavan Agrawal
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# AuthorizationNext
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/authorization_next`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'authorization_next'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install authorization_next
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/authorization_next. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
40
|
+
|
41
|
+
## Code of Conduct
|
42
|
+
|
43
|
+
Everyone interacting in the AuthorizationNext project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/authorization/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "authorization_next/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "authorization_next"
|
9
|
+
spec.version = AuthorizationNext::VERSION
|
10
|
+
spec.authors = ["Pavan Agrawal"]
|
11
|
+
spec.email = ["pavan.agrawala@gmail.com"]
|
12
|
+
|
13
|
+
spec.summary = %q{Converted plugin to gem which will work with association as well.}
|
14
|
+
spec.description = %q{Converted plugin to gem which will work with association as well.}
|
15
|
+
spec.homepage = "https://github.com/pavanagrawal/authorization_next"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
# Specify which files should be added to the gem when it is released.
|
19
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
|
+
end
|
23
|
+
spec.bindir = "exe"
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
28
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "authorization_next"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
require "authorization_next/version"
|
2
|
+
require File.dirname(__FILE__) + '/authorization_next/publishare/exceptions'
|
3
|
+
require File.dirname(__FILE__) + '/authorization_next/publishare/parser'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
module AuthorizationNext
|
8
|
+
module Base
|
9
|
+
|
10
|
+
# Modify these constants in your environment.rb to tailor the plugin to your authentication system
|
11
|
+
if not Object.constants.include? "DEFAULT_REDIRECTION_HASH"
|
12
|
+
DEFAULT_REDIRECTION_HASH = { :controller => 'account', :action => 'login' }
|
13
|
+
end
|
14
|
+
if not Object.constants.include? "STORE_LOCATION_METHOD"
|
15
|
+
STORE_LOCATION_METHOD = :store_return_location
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included( recipient )
|
19
|
+
recipient.extend( ControllerClassMethods )
|
20
|
+
recipient.class_eval do
|
21
|
+
include ControllerInstanceMethods
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ControllerClassMethods
|
26
|
+
|
27
|
+
# Allow class-level authorization_next check.
|
28
|
+
# permit is used in a before_filter fashion and passes arguments to the before_filter.
|
29
|
+
def permit( authorization_expression, *args )
|
30
|
+
filter_keys = [ :only, :except ]
|
31
|
+
filter_args, eval_args = {}, {}
|
32
|
+
if args.last.is_a? Hash
|
33
|
+
filter_args.merge!( args.last.reject {|k,v| not filter_keys.include? k } )
|
34
|
+
eval_args.merge!( args.last.reject {|k,v| filter_keys.include? k } )
|
35
|
+
end
|
36
|
+
before_filter( filter_args ) do |controller|
|
37
|
+
controller.permit( authorization_expression, eval_args )
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module ControllerInstanceMethods
|
43
|
+
include AuthorizationNext::Base::EvalParser # RecursiveDescentParser is another option
|
44
|
+
|
45
|
+
# Permit? turns off redirection by default and takes no blocks
|
46
|
+
def permit?( authorization_expression, *args )
|
47
|
+
@options = { :allow_guests => false, :redirect => false }
|
48
|
+
@options.merge!( args.last.is_a?( Hash ) ? args.last : {} )
|
49
|
+
|
50
|
+
has_permission?( authorization_expression )
|
51
|
+
end
|
52
|
+
|
53
|
+
# Allow method-level authorization_next checks.
|
54
|
+
# permit (without a question mark ending) calls redirect on denial by default.
|
55
|
+
# Specify :redirect => false to turn off redirection.
|
56
|
+
def permit( authorization_expression, *args )
|
57
|
+
@options = { :allow_guests => false, :redirect => true }
|
58
|
+
@options.merge!( args.last.is_a?( Hash ) ? args.last : {} )
|
59
|
+
|
60
|
+
if has_permission?( authorization_expression )
|
61
|
+
yield if block_given?
|
62
|
+
elsif @options[:redirect]
|
63
|
+
handle_redirection
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def has_permission?( authorization_expression )
|
70
|
+
@current_user = get_user
|
71
|
+
if not @options[:allow_guests]
|
72
|
+
if @current_user.nil? # We aren't logged in, or an exception has already been raised
|
73
|
+
return false
|
74
|
+
elsif not @current_user.respond_to? :id
|
75
|
+
raise( UserDoesntImplementID, "User doesn't implement #id")
|
76
|
+
elsif not @current_user.respond_to? :has_role?
|
77
|
+
raise( UserDoesntImplementRoles, "User doesn't implement #has_role?" )
|
78
|
+
end
|
79
|
+
end
|
80
|
+
parse_authorization_expression( authorization_expression )
|
81
|
+
end
|
82
|
+
|
83
|
+
# Handle redirection within permit if authorization is denied.
|
84
|
+
def handle_redirection
|
85
|
+
return if not self.respond_to?( :redirect_to )
|
86
|
+
redirection = DEFAULT_REDIRECTION_HASH
|
87
|
+
redirection[:controller] = @options[:redirect_controller] if @options[:redirect_controller]
|
88
|
+
redirection[:action] = @options[:redirect_action] if @options[:redirect_action]
|
89
|
+
|
90
|
+
# Store url in session for return if this is available from authentication
|
91
|
+
send( STORE_LOCATION_METHOD ) if respond_to? STORE_LOCATION_METHOD
|
92
|
+
if @current_user
|
93
|
+
flash[:notice] = "Permission denied. Your account cannot access the requested page."
|
94
|
+
else
|
95
|
+
flash[:notice] = @options[:redirect_message] ? @options[:redirect_message] : "Login is required"
|
96
|
+
end
|
97
|
+
redirect_to redirection
|
98
|
+
false # Want to short-circuit the filters
|
99
|
+
end
|
100
|
+
|
101
|
+
# Try to find current user by checking options hash and instance method in that order.
|
102
|
+
def get_user
|
103
|
+
if @options[:user]
|
104
|
+
@options[:user]
|
105
|
+
elsif @options[:get_user_method]
|
106
|
+
send( @options[:get_user_method] )
|
107
|
+
elsif self.respond_to? :current_user
|
108
|
+
current_user
|
109
|
+
elsif not @options[:allow_guests]
|
110
|
+
raise( CannotObtainUserObject, "Couldn't find #current_user or @user, and nothing appropriate found in hash" )
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Try to find a model to query for permissions
|
115
|
+
def get_model( str )
|
116
|
+
if str =~ /\s*([A-Z]+\w*)\s*/
|
117
|
+
# Handle model class
|
118
|
+
begin
|
119
|
+
Module.const_get( str )
|
120
|
+
rescue
|
121
|
+
raise CannotObtainModelClass, "Couldn't find model class: #{str}"
|
122
|
+
end
|
123
|
+
elsif str =~ /\s*:*(\w+)\s*/
|
124
|
+
# Handle model instances
|
125
|
+
model_name = $1
|
126
|
+
model_symbol = model_name.to_sym
|
127
|
+
if @options[model_symbol]
|
128
|
+
@options[model_symbol]
|
129
|
+
elsif instance_variables.include?( '@'+model_name )
|
130
|
+
instance_variable_get( '@'+model_name )
|
131
|
+
# Note -- while the following code makes autodiscovery more convenient, it's a little too much side effect & security question
|
132
|
+
# elsif self.params[:id]
|
133
|
+
# eval_str = model_name.camelize + ".find(#{self.params[:id]})"
|
134
|
+
# eval eval_str
|
135
|
+
else
|
136
|
+
raise CannotObtainModelObject, "Couldn't find model (#{str}) in hash or as an instance variable"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
ActionController::Base.send( :include, AuthorizationNext::Base )
|
147
|
+
ActionView::Base.send( :include, AuthorizationNext::Base::ControllerInstanceMethods )
|
148
|
+
|
149
|
+
# You can perform authorization at varying degrees of complexity.
|
150
|
+
# Choose a style of authorization below (see README) and the appropriate
|
151
|
+
# mixin will be used for your app.
|
152
|
+
|
153
|
+
# When used with the auth_test app, we define this in config/environment.rb
|
154
|
+
# AUTHORIZATION_MIXIN = "hardwired"
|
155
|
+
if not Object.constants.include? "AUTHORIZATION_MIXIN"
|
156
|
+
AUTHORIZATION_MIXIN = "object roles"
|
157
|
+
end
|
158
|
+
|
159
|
+
case AUTHORIZATION_MIXIN
|
160
|
+
when "hardwired"
|
161
|
+
require "authorization_next/publishare/hardwired_roles"
|
162
|
+
ActiveRecord::Base.send( :include,
|
163
|
+
AuthorizationNext::HardwiredRoles::UserExtensions,
|
164
|
+
AuthorizationNext::HardwiredRoles::ModelExtensions
|
165
|
+
)
|
166
|
+
when "object roles"
|
167
|
+
require "authorization_next/publishare/object_roles_table"
|
168
|
+
ActiveRecord::Base.send( :include,
|
169
|
+
AuthorizationNext::ObjectRolesTable::UserExtensions,
|
170
|
+
AuthorizationNext::ObjectRolesTable::ModelExtensions
|
171
|
+
)
|
172
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module AuthorizationNext #:nodoc:
|
2
|
+
|
3
|
+
# Base error class for AuthorizationNext module
|
4
|
+
class AuthorizationError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
# Raised when the authorization expression is invalid (cannot be parsed)
|
8
|
+
class AuthorizationExpressionInvalid < AuthorizationError
|
9
|
+
end
|
10
|
+
|
11
|
+
# Raised when we can't find the current user
|
12
|
+
class CannotObtainUserObject < AuthorizationError
|
13
|
+
end
|
14
|
+
|
15
|
+
# Raised when an authorization expression contains a model class that doesn't exist
|
16
|
+
class CannotObtainModelClass < AuthorizationError
|
17
|
+
end
|
18
|
+
|
19
|
+
# Raised when an authorization expression contains a model reference that doesn't exist
|
20
|
+
class CannotObtainModelObject < AuthorizationError
|
21
|
+
end
|
22
|
+
|
23
|
+
# Raised when the obtained user object doesn't implement #id
|
24
|
+
class UserDoesntImplementID < AuthorizationError
|
25
|
+
end
|
26
|
+
|
27
|
+
# Raised when the obtained user object doesn't implement #has_role?
|
28
|
+
class UserDoesntImplementRoles < AuthorizationError
|
29
|
+
end
|
30
|
+
|
31
|
+
# Raised when the obtained model doesn't implement #accepts_role?
|
32
|
+
class ModelDoesntImplementRoles < AuthorizationError
|
33
|
+
end
|
34
|
+
|
35
|
+
class CannotSetRoleWhenHardwired < AuthorizationError
|
36
|
+
end
|
37
|
+
|
38
|
+
class CannotSetObjectRoleWhenSimpleRoleTable < AuthorizationError
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/exceptions'
|
2
|
+
|
3
|
+
# In order to use this mixin, you'll need to define roles by overriding the
|
4
|
+
# following functions:
|
5
|
+
#
|
6
|
+
# User#has_role?(role)
|
7
|
+
# Return true or false depending on the roles (strings) passed in.
|
8
|
+
#
|
9
|
+
# Model#accepts_role?(role, user)
|
10
|
+
# Return true or false depending on the roles (strings) this particular user has for
|
11
|
+
# this particular model object.
|
12
|
+
#
|
13
|
+
# See http://www.writertopia.com/developers/authorization
|
14
|
+
|
15
|
+
module AuthorizationNext
|
16
|
+
module HardwiredRoles
|
17
|
+
|
18
|
+
module UserExtensions
|
19
|
+
def self.included( recipient )
|
20
|
+
recipient.extend( ClassMethods )
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def acts_as_authorized_user
|
25
|
+
include AuthorizationNext::HardwiredRoles::UserExtensions::InstanceMethods
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module InstanceMethods
|
30
|
+
# If roles aren't explicitly defined in user class then return false
|
31
|
+
def has_role?( role, authorizable_object = nil )
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_role( role, authorizable_object = nil )
|
36
|
+
raise( CannotSetRoleWhenHardwired,
|
37
|
+
"Hardwired mixin: Cannot set user to role #{role}. Don't use #has_role, use code in models."
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def has_no_role( role, authorizable_object = nil )
|
42
|
+
raise( CannotSetRoleWhenHardwired,
|
43
|
+
"Hardwired mixin: Cannot remove user role #{role}. Don't use #has_no_role, use code in models."
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module ModelExtensions
|
50
|
+
def self.included( recipient )
|
51
|
+
recipient.extend( ClassMethods )
|
52
|
+
end
|
53
|
+
|
54
|
+
module ClassMethods
|
55
|
+
def acts_as_authorizable
|
56
|
+
include AuthorizationNext::HardwiredRoles::ModelExtensions::InstanceMethods
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceMethods
|
61
|
+
def accepts_role?( role, user )
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
def accepts_role( role, user )
|
66
|
+
raise( CannotSetRoleWhenHardwired,
|
67
|
+
"Hardwired mixin: Cannot set user to role #{role}. Don't use #accepts_role, use code in models."
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def accepts_no_role( role, user )
|
72
|
+
raise( CannotSetRoleWhenHardwired,
|
73
|
+
"Hardwired mixin: Cannot set user to role #{role}. Don't use #accepts_no_role, use code in models."
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/exceptions'
|
2
|
+
|
3
|
+
# Provides the appearance of dynamically generated methods on the roles database.
|
4
|
+
#
|
5
|
+
# Examples:
|
6
|
+
# user.is_member? --> Returns true if user has any role of "member"
|
7
|
+
# user.is_member_of? this_workshop --> Returns true/false. Must have authorizable object after query.
|
8
|
+
# user.is_eligible_for [this_award] --> Gives user the role "eligible" for "this_award"
|
9
|
+
# user.is_moderator --> Gives user the general role "moderator" (not tied to any class or object)
|
10
|
+
# user.is_candidate_of_what --> Returns array of objects for which this user is a "candidate"
|
11
|
+
#
|
12
|
+
# model.has_members --> Returns array of users which have role "member" on that model
|
13
|
+
# model.has_members? --> Returns true/false
|
14
|
+
#
|
15
|
+
module AuthorizationNext
|
16
|
+
module Identity
|
17
|
+
|
18
|
+
module UserExtensions
|
19
|
+
module InstanceMethods
|
20
|
+
|
21
|
+
def method_missing( method_sym, *args )
|
22
|
+
method_name = method_sym.to_s
|
23
|
+
authorizable_object = args.empty? ? nil : args[0]
|
24
|
+
|
25
|
+
base_regex = "is_(\\w+)"
|
26
|
+
fancy_regex = base_regex + "_(#{AuthorizationNext::Base::VALID_PREPOSITIONS_PATTERN})"
|
27
|
+
is_either_regex = '^((' + fancy_regex + ')|(' + base_regex + '))'
|
28
|
+
base_not_regex = "is_no[t]?_(\\w+)"
|
29
|
+
fancy_not_regex = base_not_regex + "_(#{AuthorizationNext::Base::VALID_PREPOSITIONS_PATTERN})"
|
30
|
+
is_not_either_regex = '^((' + fancy_not_regex + ')|(' + base_not_regex + '))'
|
31
|
+
|
32
|
+
if method_name =~ Regexp.new(is_either_regex + '_what$')
|
33
|
+
role_name = $3 || $6
|
34
|
+
has_role_for_objects(role_name)
|
35
|
+
elsif method_name =~ Regexp.new(is_not_either_regex + '\?$')
|
36
|
+
role_name = $3 || $6
|
37
|
+
not is_role?( role_name, authorizable_object )
|
38
|
+
elsif method_name =~ Regexp.new(is_either_regex + '\?$')
|
39
|
+
role_name = $3 || $6
|
40
|
+
is_role?( role_name, authorizable_object )
|
41
|
+
elsif method_name =~ Regexp.new(is_not_either_regex + '$')
|
42
|
+
role_name = $3 || $6
|
43
|
+
is_no_role( role_name, authorizable_object )
|
44
|
+
elsif method_name =~ Regexp.new(is_either_regex + '$')
|
45
|
+
role_name = $3 || $6
|
46
|
+
is_role( role_name, authorizable_object )
|
47
|
+
else
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def is_role?( role_name, authorizable_object )
|
55
|
+
if authorizable_object.nil?
|
56
|
+
return self.has_role?(role_name)
|
57
|
+
elsif authorizable_object.respond_to?(:accepts_role?)
|
58
|
+
return self.has_role?(role_name, authorizable_object)
|
59
|
+
end
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def is_no_role( role_name, authorizable_object = nil )
|
64
|
+
if authorizable_object.nil?
|
65
|
+
self.has_no_role role_name
|
66
|
+
else
|
67
|
+
self.has_no_role role_name, authorizable_object
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def is_role( role_name, authorizable_object = nil )
|
72
|
+
if authorizable_object.nil?
|
73
|
+
self.has_role role_name
|
74
|
+
else
|
75
|
+
self.has_role role_name, authorizable_object
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_role_for_objects(role_name)
|
80
|
+
roles = self.roles.find_all_by_name( role_name )
|
81
|
+
roles.collect do |role|
|
82
|
+
if role.authorizable_id.nil?
|
83
|
+
role.authorizable_type.nil? ?
|
84
|
+
nil : Module.const_get( role.authorizable_type ) # Returns class
|
85
|
+
else
|
86
|
+
role.authorizable
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module ModelExtensions
|
94
|
+
module InstanceMethods
|
95
|
+
|
96
|
+
def method_missing( method_sym, *args )
|
97
|
+
method_name = method_sym.to_s
|
98
|
+
if method_name =~ /^has_(\w+)\?$/
|
99
|
+
role_name = $1.singularize
|
100
|
+
self.accepted_roles.find_all_by_name(role_name).any? { |role| role.users }
|
101
|
+
elsif method_name =~ /^has_(\w+)$/
|
102
|
+
role_name = $1.singularize
|
103
|
+
users = self.accepted_roles.find_all_by_name(role_name).collect { |role| role.users }
|
104
|
+
users.flatten.uniq if users
|
105
|
+
else
|
106
|
+
super
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def respond_to? method_sym
|
111
|
+
method_name = method_sym.to_s
|
112
|
+
if method_name =~ /^has_(\w+)\?$/
|
113
|
+
true
|
114
|
+
elsif method_name =~ /^has_(\w+)$/
|
115
|
+
true
|
116
|
+
else
|
117
|
+
super
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|