conduct 0.1.14

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0c9b3822ec5762a6ba425318b04d4ef94fb03a26
4
+ data.tar.gz: 7d0cb343c896041219c9af3d2d8134a960768679
5
+ SHA512:
6
+ metadata.gz: d531afe236c05a3c67807d40214f87476c1b68f87688c89a12893955f7119c3c1d9c8c79c7acf7b76df298519072f977dcb4d5418be084cdfae598cf380063b0
7
+ data.tar.gz: 38e593631fab7e38528b586c24fce7fd72fb6e52e1ade4473868dcff69ddbd25523f0eaff3c7ed23e8d0b66a18ca5726ada1fa82634f7432fb1016b41cfcd146
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Bryan Goines
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,91 @@
1
+ Conduct - A lightweight authorization
2
+ ---
3
+
4
+ This is work in progress. README will be updated/improved when this is completed.
5
+
6
+
7
+ ### Examples:
8
+
9
+ **app/abilities/post_ability.rb**
10
+
11
+ ```ruby
12
+ module PostAbility
13
+
14
+ include Conduct
15
+
16
+ can :write, Post do |post|
17
+ current_user.present? && post.new_record?
18
+ end
19
+
20
+ can :read, Post do |post|
21
+ post.user == current_user
22
+ end
23
+
24
+ end
25
+
26
+ ```
27
+
28
+ **app/abilities/ability.rb**
29
+
30
+ ```ruby
31
+ class Ability
32
+
33
+ include Conduct
34
+
35
+ define_action create: [:new, :create]
36
+ define_action read: [:index, :show]
37
+ define_action update: [:edit, :update]
38
+ define_action delete: [:destroy]
39
+
40
+ define_action manage: [:create, :read, :update, :delete]
41
+
42
+ can :manage, :all do
43
+ current_user.present? && current_user.admin?
44
+ end
45
+
46
+ include PostAbility
47
+
48
+ can :comment, Post, :create_comment?
49
+
50
+ can :create, Comment, do |comment|
51
+ false
52
+ end
53
+
54
+ def create_comment?(post)
55
+ can? :create, post.comments.new
56
+ end
57
+
58
+ end
59
+
60
+ ```
61
+
62
+ **app/controllers/posts_controller.rb**
63
+
64
+ ```ruby
65
+ class PostsController < ApplicationController
66
+ before_filter :authorize_ability! only: [:new, :create]
67
+
68
+ def index
69
+ if authorize_ability
70
+ @posts = @user.posts
71
+ else
72
+ @posts = @user.posts.public
73
+ end
74
+ end
75
+
76
+ def edit
77
+ redirect_to root_url unless can?(:update, @post)
78
+ end
79
+
80
+ ...
81
+
82
+ end
83
+ ```
84
+
85
+ **app/views/posts/index.html.erb**
86
+
87
+ ```ruby
88
+ <% if can?(:create, @post) %>
89
+ <%= link_to "New Post", new_post_path %>
90
+ <% end %>
91
+ ```
@@ -0,0 +1,132 @@
1
+ $LOAD_PATH.unshift 'lib'
2
+
3
+ unless defined?(ActiveSupport)
4
+ require 'active_support/concern'
5
+ require 'active_support/core_ext/array'
6
+ end
7
+
8
+ require 'conduct/rule'
9
+
10
+ module Conduct
11
+ extend ActiveSupport::Concern
12
+
13
+ module ClassMethods
14
+
15
+ attr_accessor :current_user
16
+
17
+ def current_user
18
+ @@current_user
19
+ end
20
+
21
+ def current_user=(user)
22
+ @@current_user = user
23
+ end
24
+
25
+ def rules
26
+ @@rules ||= {}
27
+ end
28
+
29
+ def actions
30
+ @@actions ||= {}
31
+ end
32
+
33
+ def define_action(*args)
34
+ options = args.extract_options!
35
+ options.each do |key, value|
36
+ actions[key] = value
37
+ end
38
+ end
39
+
40
+ def can(action, subject, *args, &block)
41
+ options = args.extract_options!
42
+ block = args.pop if args.last.kind_of?(Proc)
43
+ if defined_action_exists?(action)
44
+ collection = fetch_action_from_collection(action)
45
+ collection.each { |name| define_rule(name, subject, options, &block) }
46
+ end
47
+ define_rule(action, subject, options, &block)
48
+ end
49
+
50
+ private
51
+
52
+ def define_rule(action, subject, options, &block)
53
+ if defined_action_exists?(action)
54
+ add_rule_for_defined_action(action, subject, options, &block)
55
+ end
56
+ if action.is_a?(Array)
57
+ action.each do |name|
58
+ rule = Rule.new(name, subject, options, &block)
59
+ add_rule(rule.name, rule)
60
+ end
61
+ else
62
+ rule = Rule.new(action, subject, options, &block)
63
+ add_rule(rule.name, rule)
64
+ end
65
+ end
66
+
67
+ def add_rule(name, rule)
68
+ rules[name] = rule unless rule_exists?(rule.name)
69
+ end
70
+
71
+ def add_rule_for_defined_action(action, subject, options, &block)
72
+ collection = fetch_action_from_collection(action)
73
+ collection.each do |name|
74
+ rule = Rule.new(name, subject, options, &block)
75
+ add_rule(rule.name, rule)
76
+ end
77
+ end
78
+
79
+ def rule_exists?(name)
80
+ rules[name].present?
81
+ end
82
+
83
+ def defined_action_exists?(action)
84
+ actions[action].present?
85
+ end
86
+
87
+ def fetch_action_from_collection(action)
88
+ list = actions[action]
89
+ fail 'Please define action as collection' unless list.is_a?(Array)
90
+ list
91
+ end
92
+
93
+ end
94
+
95
+ attr_reader :current_user
96
+
97
+ def initialize(user)
98
+ @current_user = self.class.current_user = user
99
+ end
100
+
101
+ def rules
102
+ @rules ||= self.class.rules
103
+ end
104
+
105
+ def can?(action, subject, options = {})
106
+ name = build_name_for(action, subject)
107
+ rule = rules[name] || rules["#{action}_all"]
108
+ return false unless rule
109
+ rule.result(subject, options)
110
+ end
111
+
112
+ def cannot?(*args)
113
+ !can?(*args)
114
+ end
115
+
116
+ private
117
+
118
+ def build_name_for(action, subject)
119
+ subject = find_class(subject)
120
+ "#{action}_#{subject.to_s.downcase}"
121
+ end
122
+
123
+ def find_class(subject)
124
+ return subject.model_name if subject.respond_to?(:model_name)
125
+ return subject.class.model_name if subject.class.respond_to?(:model_name)
126
+ return find_class(subject.first) if subject.is_a?(Array)
127
+ subject.is_a?(Class) ? subject : subject.class
128
+ end
129
+
130
+ end
131
+
132
+ require 'conduct/rails' if defined?(Rails)
@@ -0,0 +1,53 @@
1
+ module Conduct
2
+ module Rails
3
+ module Helpers
4
+
5
+ def ability_object(user)
6
+ @ability ||= Ability.new(user)
7
+ end
8
+
9
+ def current_ability
10
+ @ability ||= Ability.new(current_user)
11
+ end
12
+
13
+ def can?(*args)
14
+ current_ability.can?(*args)
15
+ end
16
+
17
+ def cannot?(*args)
18
+ current_ability.cannot?(*args)
19
+ end
20
+
21
+ # if authorize_ability
22
+ # @posts = current_user.posts
23
+ # else
24
+ # @posts = @user.posts.public
25
+ # end
26
+ def authorize_ability
27
+ return unless defined?(controller_name) || params[:action].present?
28
+ klass = _classify_controller_name
29
+ current_ability.can?(params[:action], klass.new)
30
+ end
31
+
32
+ # before_action :authorize_ability!
33
+ def authorize_ability!
34
+ fail 'Access Denied' unless authorize_ability
35
+ end
36
+
37
+ private
38
+
39
+ def _classify_controller_name
40
+ controller_name.classify.constantize
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+
47
+ if defined?(ActionController::Base)
48
+ ActionController::Base.class_eval do
49
+ include Conduct::Rails::Helpers
50
+ helper_method :can?, :cannot?, :current_ability, :ability_object
51
+ hide_action :authorize_ability, :authorize_ability!
52
+ end
53
+ end
@@ -0,0 +1,35 @@
1
+ module Conduct
2
+ class Rule
3
+
4
+ attr_accessor :action, :subject, :options, :block
5
+ attr_reader :name, :value
6
+
7
+ def initialize(action, subject, options = {}, &block)
8
+ @action = action
9
+ @subject = subject
10
+ @options = options
11
+ @block = block
12
+ @value = nil
13
+ @name = "#{action}_#{subject.to_s.downcase}"
14
+ end
15
+
16
+ def result(object, opts = {})
17
+ if object.respond_to?(:to_a)
18
+ @value = object.to_a.all? { |obj| block_call(obj, opts) }
19
+ else
20
+ @value = block_call(object, opts)
21
+ end
22
+ fail 'Result value is not a boolean type' unless boolean_value?
23
+ @value
24
+ end
25
+
26
+ def block_call(obj, opts = {})
27
+ opts.any? ? block.call(obj, opts) : block.call(obj)
28
+ end
29
+
30
+ def boolean_value?
31
+ value.kind_of?(TrueClass) || value.kind_of?(FalseClass)
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module Conduct
2
+ VERSION = '0.1.14'
3
+ end
@@ -0,0 +1,22 @@
1
+ module Conduct
2
+ module Generators
3
+ class AbilityGenerator < ::Rails::Generators::NamedBase
4
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
5
+
6
+ hook_for :orm
7
+
8
+ desc "Create a new ability"
9
+
10
+ def create_ability
11
+ template 'ability_module.rb', File.join('app/abilities', class_path, "#{file_name}_ability.rb")
12
+ inject_into_file 'app/abilities/ability.rb', after: "include Conduct\n" do
13
+ "\n include #{class_name}Activity\n"
14
+ end
15
+
16
+ end
17
+
18
+
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ module <%= class_name %>Ability
2
+
3
+ include Conduct
4
+
5
+ can :manage, <%= class_name %> do |<%= class_name.downcase %>|
6
+ false
7
+ end
8
+
9
+ end
@@ -0,0 +1,14 @@
1
+ module Conduct
2
+ module Generators
3
+ class InstallGenerator < ::Rails::Generators::Base
4
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
5
+
6
+ desc "Creates an ability to your application"
7
+
8
+ def copy_ability
9
+ template 'ability.rb', 'app/abilities/ability.rb'
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ class Ability
2
+
3
+ include Conduct
4
+
5
+ define_action create: [:new, :create]
6
+ define_action read: [:index, :show]
7
+ define_action update: [:edit, :update]
8
+ define_action delete: [:destroy]
9
+
10
+ define_action manage: [:create, :read, :update, :delete]
11
+
12
+
13
+ can :manage, :all do
14
+ # current_user.admin?
15
+ false
16
+ end
17
+
18
+ #include ExampleAbility
19
+
20
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: conduct
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.14
5
+ platform: ruby
6
+ authors:
7
+ - Bryan Goines
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description:
28
+ email: bryann83@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - LICENSE
34
+ - README.md
35
+ - lib/conduct.rb
36
+ - lib/conduct/rails.rb
37
+ - lib/conduct/rule.rb
38
+ - lib/conduct/version.rb
39
+ - lib/generators/conduct/ability/ability_generator.rb
40
+ - lib/generators/conduct/ability/templates/ability_module.rb
41
+ - lib/generators/conduct/install/install_generator.rb
42
+ - lib/generators/conduct/install/templates/ability.rb
43
+ homepage: https://github.com/bry4n/conduct
44
+ licenses: []
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.2.2
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: Simple authorization
66
+ test_files: []