access_rules 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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in access_rules.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # AccessRules
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'access_rules'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install access_rules
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,13 @@
1
+ require "access_rules/version"
2
+ require "access_rules/rules"
3
+ require "access_rules/defining"
4
+ require "access_rules/checking"
5
+
6
+ module AccessRules
7
+ # Your code goes here...
8
+ end
9
+
10
+ ActiveRecord::Base.send( :include, AccessRules::Defining )
11
+ ActionController::Base.send( :include, AccessRules::Checking::ControllerMethods )
12
+ # TODO: this should not be included in Object
13
+ Object.send( :include, AccessRules::Checking::InstanceMethods )
@@ -0,0 +1,38 @@
1
+ module AccessRules
2
+ module Checking
3
+
4
+ module ControllerMethods
5
+
6
+ def self.included(klass)
7
+ klass.class_eval do
8
+ helper_method :check_action_rules, :check_current_action_rules
9
+ end
10
+ end
11
+
12
+ # We assume controller here
13
+ def check_current_action_rules( object, user, site = nil )
14
+ check_action_rules( params[:action], object, user, site )
15
+ end
16
+
17
+ # Controller need to respond to action_rules method
18
+ def check_action_rules( action, object, user, site = nil )
19
+ rule = action_rules[action.to_sym] || action_rules[:default]
20
+ if rule
21
+ result = rule.check( object, user, site )
22
+ return result
23
+ else
24
+ return true
25
+ end
26
+ end
27
+ end
28
+
29
+ module InstanceMethods
30
+
31
+ def rule( rule_name )
32
+ return Rules::Base.new( rule_name )
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ module AccessRules
2
+ module Defining
3
+
4
+ def self.included(klass)
5
+ klass.class_eval do
6
+ class_attribute :rules
7
+ self.rules = {}
8
+ end
9
+ klass.extend( ClassMethods )
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ # Defines rules one by one
15
+ def define_rule( name, rule )
16
+ # class_attribute requires that the var is reassigned to make it override the inherited one
17
+ self.rules = self.rules.merge( name.to_sym => rule )
18
+ end
19
+
20
+ # Defines all rules at once
21
+ def define_rules( rules )
22
+ self.rules = rules
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,112 @@
1
+ module AccessRules::Rules
2
+
3
+ class Base
4
+
5
+ # Creates a rule given its name. Name is a dot-separated string, eg:
6
+ # forum_post.forum_thread.forum.group.member
7
+ # where
8
+ # forum_post - name of initial object class
9
+ # forum_thread.forum.group - associations to traverse: last one is supposed
10
+ # to contain the rule itself. Associations may be omitted - in this case
11
+ # initial object should contain the rule
12
+ # member - name of rule. This may be a rule defined using define_rule(s) or
13
+ # just a name of method in rule class. If it's a method it must accept:
14
+ # TODO: disregard that, now only no-arg methods work
15
+ # 2 arguments - user, site
16
+ # 1 arguments - user
17
+ # 0 arguments
18
+ # and return true/false indicating whether the rules succeeded
19
+ def initialize( rule_name )
20
+ @rule_name = rule_name
21
+ elems = rule_name.split( '.' )
22
+ klass = elems.shift.classify.constantize
23
+ proc_or_method = elems.pop
24
+ @associations = elems.dup
25
+ @associations.each do |assoc|
26
+ reflection = klass.reflect_on_association( assoc.to_sym )
27
+ raise "No rule named #{rule_name}, failed token: #{assoc}" unless reflection
28
+ klass = reflection.class_name.constantize
29
+ end
30
+ @proc = klass.rules[proc_or_method.to_sym]
31
+ unless @proc
32
+ @method_name = proc_or_method
33
+ # TODO: method_defined? fails for attribute accessors
34
+ #raise "No rule named #{rule_name}, failed token: #{@method_name}" unless klass.method_defined?( @method_name )
35
+ end
36
+ end
37
+
38
+ def check( object, user, site = nil )
39
+ # XXX: we assume has_one or belongs_to association here
40
+ object_to_check = @associations.inject( object ) { |obj, assoc| obj.send( assoc ) }
41
+
42
+ if @proc
43
+ result = @proc.call( object_to_check, user, site )
44
+ else
45
+ # TODO: check if object.class matches klass (from initialize)
46
+ result = object_to_check.send( @method_name )
47
+ # TODO: the code below fails eg. for forum.public?
48
+ #method = object_to_check.method( @method_name )
49
+ #result = case method.arity
50
+ #when 0
51
+ # method.call
52
+ #when 1
53
+ # method.call( user )
54
+ #when 2
55
+ # method.call( user, site )
56
+ #else
57
+ # raise "Can't use method #{@method_name} on #{object_to_check} with arity #{method.arity} for access rule #{@rule_name} (arity out of (0..2) range)"
58
+ #end
59
+ end
60
+ Rails.logger.debug( "----------access rule check: #{@rule_name}: #{result}" )
61
+ return result
62
+ end
63
+
64
+ # AND rule
65
+ def & (rule)
66
+ return And.new( self, rule )
67
+ end
68
+
69
+ # OR rule
70
+ def | (rule)
71
+ return Or.new( self, rule )
72
+ end
73
+
74
+ # NOT rule
75
+ def ~
76
+ Not.new( @rule_name )
77
+ end
78
+ end
79
+
80
+ class And < Base
81
+
82
+ def initialize( *rules )
83
+ @rules = rules
84
+ end
85
+
86
+ def check( object, user, site = nil )
87
+ @rules.all? { |rule| rule.check( object, user, site ) }
88
+ end
89
+
90
+ end
91
+
92
+ class Or < Base
93
+
94
+ def initialize( *rules )
95
+ @rules = rules
96
+ end
97
+
98
+ def check( object, user, site = nil )
99
+ @rules.any? { |rule| rule.check( object, user, site ) }
100
+ end
101
+
102
+ end
103
+
104
+ class Not < Base
105
+
106
+ def check( object, user, site = nil )
107
+ ! super
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,3 @@
1
+ module AccessRules
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'test/unit'
3
+
4
+ class AccessRulesTest < Test::Unit::TestCase
5
+ # Replace this with your real tests.
6
+ def test_this_plugin
7
+ flunk
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: access_rules
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marek Janukowicz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Authorization for Rails
15
+ email:
16
+ - marek@janukowicz.net
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/access_rules/checking.rb
22
+ - lib/access_rules/version.rb
23
+ - lib/access_rules/defining.rb
24
+ - lib/access_rules/rules.rb
25
+ - lib/access_rules.rb
26
+ - Gemfile
27
+ - LICENSE.txt
28
+ - Rakefile
29
+ - README.md
30
+ - test/access_rules_test.rb
31
+ homepage: ''
32
+ licenses: []
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.24
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: ''
55
+ test_files:
56
+ - test/access_rules_test.rb