can_camel 0.1.0 → 0.2.1
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.
- 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
|