can_camel 0.1.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +65 -0
- data/lib/can_camel.rb +1 -1
- data/lib/can_camel/base.rb +2 -2
- data/lib/can_camel/filters.rb +2 -4
- data/lib/can_camel/group_node.rb +3 -4
- data/lib/can_camel/linter.rb +2 -4
- data/lib/can_camel/node.rb +5 -9
- data/lib/can_camel/version.rb +1 -1
- data/lib/generators/can_camel/config/initializers/can_camel.rb +1 -0
- data/lib/generators/can_camel/db/migrate/00000000000002_hstore_to_json.rb +14 -0
- data/lib/generators/can_camel/install_generator.rb +1 -0
- metadata +10 -9
- data/lib/can_camel/filter_helper.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cd2a7e24ff8c42df996b7255ecfc0710ae5b011
|
4
|
+
data.tar.gz: 97d7813911fdbbcc34c765243df8f047fceef026
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89e48cc509dfe2269a5f308e3234fbcbe2400642b22c916b44937b72f32fcbfb57eaa28de6d4162b23e4d69f37cd4a6a222ca79270994faf6a29d0ff01ba5338
|
7
|
+
data.tar.gz: c765a6da93ea8aa404105b405a22a8598348a5c4a42b54c36655f6c471c61d46228eeb3c077962f88c933457aa4a641ec09e641dc4d3fd3d4faf16e1b86e18e2
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
CanCamel
|
2
|
+
========
|
3
|
+
This project uses WTFPL license, requires postgresql db adapter and rocks <br>
|
4
|
+
Upstream have not been tested in production, take a lot of care
|
5
|
+
What is CanCamel?
|
6
|
+
=================
|
7
|
+
CanCamel is a ruby gem for access control. For example, we can want to know
|
8
|
+
`can camel write a poem?` We can write it as `can?(camel, :write, :poem)`
|
9
|
+
This code calls function with 3 arguments: user (actor), action and subject and returns hash or nil
|
10
|
+
For example, we can grant camel full poem access (but only for actions that exists).
|
11
|
+
We can let camel write poems only in fridays midnight, why not? Any optional params
|
12
|
+
can be passed to a filter. Any custom filters could be made and any additional data
|
13
|
+
(e.g. maximal poem length allowed) can be passed back
|
14
|
+
|
15
|
+
Step 1. Installation
|
16
|
+
====================
|
17
|
+
run rails g can_camel:install <br>
|
18
|
+
Then visit generated initializer at config/initializers/can_camel.rb
|
19
|
+
<pre>
|
20
|
+
# CanCamel::Filters.include AbilityFilters
|
21
|
+
CanCamel::TABLE_NAME = "can_camel_nodes"
|
22
|
+
CanCamel::GROUP_METHOD = :group
|
23
|
+
</pre>
|
24
|
+
First line describes how to use you own filters. You may prefer `prepend` over `include`
|
25
|
+
here. You can also specify table name, if you want. Third line describes a symbol, which references for
|
26
|
+
user model method, returning user group. Group should be a symbol. Visit spec/dummy/app/models/user.rb
|
27
|
+
for example. When you sure with this file, run generated migration.
|
28
|
+
Remember, that migration installs 'hstore' plugin, on which relies,
|
29
|
+
but does not remove it. If you want to revert it, you may want to remove plugin too
|
30
|
+
|
31
|
+
Step 2. Database structure
|
32
|
+
==========================
|
33
|
+
Database consists of nodes. Primary nodes (WHERE parent_id IS NULL) are called subjects,
|
34
|
+
Their children are called actions, and actions' children are called groups. Groups' children
|
35
|
+
are called garbage and never used. Any node can have conditions and results. Conditions' syntax is
|
36
|
+
<pre>
|
37
|
+
[
|
38
|
+
{ method: :day_of_week, allow: %w(saturday sunday) }
|
39
|
+
]
|
40
|
+
</pre>
|
41
|
+
It means, that :day_of_week will be called with `allow: {"saturday", "sunday}"` argument
|
42
|
+
|
43
|
+
Step 3. Linting
|
44
|
+
===============
|
45
|
+
If you are working primary with database (e.g. in migration), you can call
|
46
|
+
`CanCamel.lint` to check is database correct. Best way is to call `CanCamel.lint!` in transaction
|
47
|
+
with all changes done and enjoy your exception if need
|
48
|
+
|
49
|
+
Step 4. Constrains (Incomplete)
|
50
|
+
===============================
|
51
|
+
Filters have great powers, and with big power big responsibility comes. For example, you are managing
|
52
|
+
statistics access on Users, and your filter scoping them. What if your filter would be called for Blog?
|
53
|
+
I think, nothing good. To prevent it, you can write a constraint
|
54
|
+
<pre>
|
55
|
+
validate :filter_name, subject: :user
|
56
|
+
def filter_name
|
57
|
+
#TODO: do something
|
58
|
+
end
|
59
|
+
</pre>
|
60
|
+
|
61
|
+
Step 5. Human interface (NIY)
|
62
|
+
============================
|
63
|
+
Nodes supports some usefull methods to work with them
|
64
|
+
* `Node#aviable_filters` returns all filters available
|
65
|
+
* `Node#handling_params` returns list of all results available
|
data/lib/can_camel.rb
CHANGED
data/lib/can_camel/base.rb
CHANGED
@@ -3,8 +3,8 @@ module CanCamel
|
|
3
3
|
# don't delegate all, because lint_node designed to be run on same instances of linter
|
4
4
|
delegate :lint, :lint!, to: :new_linter
|
5
5
|
|
6
|
-
def can?(
|
7
|
-
Cache[[
|
6
|
+
def can?(user, action, subject, **args)
|
7
|
+
Cache[[user.send(GROUP_METHOD), action, subject]].try(:can?, args)
|
8
8
|
end
|
9
9
|
|
10
10
|
private
|
data/lib/can_camel/filters.rb
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
require 'can_camel/validators'
|
2
2
|
module CanCamel::Filters
|
3
3
|
include CanCamel::Validators
|
4
|
-
extend CanCamel::FilterHelper
|
5
4
|
ArgSyntaxError = Class.new(StandardError)
|
6
5
|
|
7
6
|
module_function
|
8
7
|
|
9
8
|
validates :at_time, :hours, presence: {}
|
10
9
|
def at_time(hours:, **_)
|
11
|
-
hours = from_int_array hours
|
12
10
|
hours.include?(Time.now.hour) && {}
|
13
11
|
end
|
14
12
|
|
15
13
|
validates :at_day, presence_of: { fields: [:days, :wdays], any: true }
|
16
14
|
def at_day(days: nil, wdays: nil, **_)
|
17
|
-
return if days && !
|
18
|
-
return if wdays && !
|
15
|
+
return if days && !days.include?(Time.now.day)
|
16
|
+
return if wdays && !wdays.include?(Time.now.wday)
|
19
17
|
{}
|
20
18
|
end
|
21
19
|
end
|
data/lib/can_camel/group_node.rb
CHANGED
@@ -5,10 +5,9 @@ module CanCamel
|
|
5
5
|
validates_presence_of :parent_id
|
6
6
|
|
7
7
|
def can?(**additional_params)
|
8
|
-
condition.each_with_object(result.dup) do |
|
9
|
-
|
10
|
-
|
11
|
-
filtered = Filters.send(hash[:method], **hash.merge(additional_params))
|
8
|
+
condition.each_with_object(result.dup) do |(method, args), result|
|
9
|
+
args = args.symbolize_keys
|
10
|
+
filtered = Filters.send(method, **args.merge(additional_params))
|
12
11
|
return unless filtered
|
13
12
|
result.merge! filtered
|
14
13
|
end || result
|
data/lib/can_camel/linter.rb
CHANGED
@@ -19,10 +19,8 @@ module CanCamel
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def validate_node(node)
|
22
|
-
node.condition.each do |
|
23
|
-
|
24
|
-
raise LintingError unless hash[:method]
|
25
|
-
Validators.validate!(filter: hash[:method], args: hash)
|
22
|
+
node.condition.each do |method, args|
|
23
|
+
Validators.validate!(filter: method, args: args.symbolize_keys)
|
26
24
|
end
|
27
25
|
true
|
28
26
|
rescue Validators::ValidationError, LintingError
|
data/lib/can_camel/node.rb
CHANGED
@@ -19,12 +19,14 @@ module CanCamel
|
|
19
19
|
|
20
20
|
validates! :inherited, absence: { message: "You should not save inherited nodes!" }
|
21
21
|
|
22
|
-
# accessors
|
23
|
-
|
24
22
|
def name
|
25
23
|
super.to_sym
|
26
24
|
end
|
27
25
|
|
26
|
+
def condition
|
27
|
+
super.symbolize_keys
|
28
|
+
end
|
29
|
+
|
28
30
|
private
|
29
31
|
|
30
32
|
attr_reader :inherited
|
@@ -36,13 +38,7 @@ module CanCamel
|
|
36
38
|
|
37
39
|
inherit_field(source, :description) { |x| self.description ||= x }
|
38
40
|
inherit_field(source, :result) { |x| result.merge!(x) { |_k, l, _r| l } }
|
39
|
-
|
40
|
-
inherit_field(source, :condition) do |new|
|
41
|
-
methods = condition.map { |c| c['method'] }
|
42
|
-
new.each do |x|
|
43
|
-
condition.push(x) unless methods.include? x['method']
|
44
|
-
end
|
45
|
-
end
|
41
|
+
inherit_field(source, :condition) { |x| self.condition = x.merge(condition) }
|
46
42
|
end
|
47
43
|
|
48
44
|
def inherit_field(source, field)
|
data/lib/can_camel/version.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
class HstoreToJson < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
unless ENV['RAILS_ENV'] == 'test' || ENV['FORCE_CAN_CAMEL_WIPE'] == 'true'
|
4
|
+
puts "Attention! This migration will wipe can_camel data. Continue? (Y/n)"
|
5
|
+
puts "Set FORCE_CAN_CAMEL_WIPE=true to automaticaly accept"
|
6
|
+
res = STDIN.gets
|
7
|
+
raise unless res =~ /\A[Yy]/
|
8
|
+
end
|
9
|
+
CanCamel::Node.delete_all
|
10
|
+
remove_column CanCamel::TABLE_NAME, :condition, :hstore, array: true, default: []
|
11
|
+
add_column CanCamel::TABLE_NAME, :condition, :json, default: {}
|
12
|
+
CanCamel::Node.delete_all
|
13
|
+
end
|
14
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: can_camel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Smirnov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,26 +16,26 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 4.2
|
19
|
+
version: '4.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 4.2
|
26
|
+
version: '4.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: pg
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description: |2
|
@@ -47,13 +47,13 @@ extensions: []
|
|
47
47
|
extra_rdoc_files: []
|
48
48
|
files:
|
49
49
|
- LICENSE
|
50
|
+
- README.md
|
50
51
|
- Rakefile
|
51
52
|
- lib/can_camel.rb
|
52
53
|
- lib/can_camel/action_node.rb
|
53
54
|
- lib/can_camel/base.rb
|
54
55
|
- lib/can_camel/cache.rb
|
55
56
|
- lib/can_camel/concern_node.rb
|
56
|
-
- lib/can_camel/filter_helper.rb
|
57
57
|
- lib/can_camel/filters.rb
|
58
58
|
- lib/can_camel/group_node.rb
|
59
59
|
- lib/can_camel/linter.rb
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- lib/can_camel/version.rb
|
64
64
|
- lib/generators/can_camel/config/initializers/can_camel.rb
|
65
65
|
- lib/generators/can_camel/db/migrate/00000000000001_create_can_camel_nodes.rb
|
66
|
+
- lib/generators/can_camel/db/migrate/00000000000002_hstore_to_json.rb
|
66
67
|
- lib/generators/can_camel/install_generator.rb
|
67
68
|
- lib/tasks/can_camel_tasks.rake
|
68
69
|
homepage: https://github.com/JelF/can_camel
|
@@ -75,9 +76,9 @@ require_paths:
|
|
75
76
|
- lib
|
76
77
|
required_ruby_version: !ruby/object:Gem::Requirement
|
77
78
|
requirements:
|
78
|
-
- - "
|
79
|
+
- - ">"
|
79
80
|
- !ruby/object:Gem::Version
|
80
|
-
version: '
|
81
|
+
version: '2.1'
|
81
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
83
|
requirements:
|
83
84
|
- - ">="
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# Holds functions to parse params from strings
|
2
|
-
module CanCamel
|
3
|
-
module FilterHelper
|
4
|
-
def from_int_array(str)
|
5
|
-
from_array(str).map(&:to_i)
|
6
|
-
rescue
|
7
|
-
raise Filters::ArgSyntaxError
|
8
|
-
end
|
9
|
-
|
10
|
-
def from_array(str)
|
11
|
-
raise Filters::ArgSyntaxError unless /\A\[(?<els>.+)\]\z/ =~ str
|
12
|
-
els.split ','
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|