can_camel 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +13 -0
- data/Rakefile +17 -0
- data/lib/can_camel.rb +8 -0
- data/lib/can_camel/action_node.rb +8 -0
- data/lib/can_camel/base.rb +16 -0
- data/lib/can_camel/cache.rb +31 -0
- data/lib/can_camel/concern_node.rb +5 -0
- data/lib/can_camel/filter_helper.rb +15 -0
- data/lib/can_camel/filters.rb +21 -0
- data/lib/can_camel/group_node.rb +17 -0
- data/lib/can_camel/linter.rb +52 -0
- data/lib/can_camel/node.rb +53 -0
- data/lib/can_camel/subject_node.rb +7 -0
- data/lib/can_camel/validators.rb +60 -0
- data/lib/can_camel/version.rb +3 -0
- data/lib/generators/can_camel/config/initializers/can_camel.rb +4 -0
- data/lib/generators/can_camel/db/migrate/00000000000001_create_can_camel_nodes.rb +18 -0
- data/lib/generators/can_camel/install_generator.rb +8 -0
- data/lib/tasks/can_camel_tasks.rake +4 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 19f8ade41da75b5b9b3beb17bc729b62fae529e3
|
4
|
+
data.tar.gz: 44fd15e4109320bc9143dd4acb992bed642955b3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f02195d10717ac041a2e64df9b893d8f2d14a91051bdaa87a3b5e4cc668dda8f4e8dc932744330d982905e8a2b216fbebc7ec7d033b02549dd3287b88e6638c2
|
7
|
+
data.tar.gz: 590a5bd7ec97794d11638630d45561b496f3279428ab8dadb83078b12b65437d6ca859de64694fe0a3ce30c7b2c6a869116f6f5c0de87bdd1e607e4b76878504
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
2
|
+
Version 2, December 2004
|
3
|
+
|
4
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
5
|
+
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
7
|
+
copies of this license document, and changing it is allowed as long
|
8
|
+
as the name is changed.
|
9
|
+
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
12
|
+
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'CanCamel'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
Bundler::GemHelper.install_tasks
|
data/lib/can_camel.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module CanCamel
|
2
|
+
module Base
|
3
|
+
# don't delegate all, because lint_node designed to be run on same instances of linter
|
4
|
+
delegate :lint, :lint!, to: :new_linter
|
5
|
+
|
6
|
+
def can?(group, action, subject, **args)
|
7
|
+
Cache[[group, action, subject]].try(:can?, args)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def new_linter
|
13
|
+
CanCamel::Linter.new
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module CanCamel
|
2
|
+
module Cache
|
3
|
+
class <<self
|
4
|
+
delegate :[], to: :cache
|
5
|
+
|
6
|
+
def reload!
|
7
|
+
@cache = build_cache
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def cache
|
13
|
+
@cache ||= build_cache
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_cache
|
17
|
+
SubjectNode.all.each_with_object({}) do |subject_node, object|
|
18
|
+
subject_name = subject_node.name
|
19
|
+
subject_node.actions.each do |action_node|
|
20
|
+
action_name = action_node.name
|
21
|
+
action_node.groups.each do |group_node|
|
22
|
+
group_name = group_node.name
|
23
|
+
group_node.inherit!
|
24
|
+
object[[group_name, action_name, subject_name]] = group_node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'can_camel/validators'
|
2
|
+
module CanCamel::Filters
|
3
|
+
include CanCamel::Validators
|
4
|
+
extend CanCamel::FilterHelper
|
5
|
+
ArgSyntaxError = Class.new(StandardError)
|
6
|
+
|
7
|
+
module_function
|
8
|
+
|
9
|
+
validates :at_time, :hours, presence: {}
|
10
|
+
def at_time(hours:, **_)
|
11
|
+
hours = from_int_array hours
|
12
|
+
hours.include?(Time.now.hour) && {}
|
13
|
+
end
|
14
|
+
|
15
|
+
validates :at_day, presence_of: { fields: [:days, :wdays], any: true }
|
16
|
+
def at_day(days: nil, wdays: nil, **_)
|
17
|
+
return if days && !from_int_array(days).include?(Time.now.day)
|
18
|
+
return if wdays && !from_int_array(wdays).include?(Time.now.wday)
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CanCamel
|
2
|
+
class GroupNode < Node
|
3
|
+
belongs_to :parent, foreign_key: :parent_id, class_name: "CanCamel::ActionNode"
|
4
|
+
|
5
|
+
validates_presence_of :parent_id
|
6
|
+
|
7
|
+
def can?(**additional_params)
|
8
|
+
condition.each_with_object(result.dup) do |hash, result|
|
9
|
+
hash.symbolize_keys!
|
10
|
+
raise Linter::LintingError unless hash[:method]
|
11
|
+
filtered = Filters.send(hash[:method], **hash.merge(additional_params))
|
12
|
+
return unless filtered
|
13
|
+
result.merge! filtered
|
14
|
+
end || result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module CanCamel
|
2
|
+
class Linter
|
3
|
+
LintingError = Class.new(StandardError)
|
4
|
+
|
5
|
+
def lint
|
6
|
+
%i(lint_inheritance lint_nodes).reduce(true) { |base, x| base && send(x) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def lint!
|
10
|
+
raise LintingError unless lint
|
11
|
+
end
|
12
|
+
|
13
|
+
def lint_node(node)
|
14
|
+
node = node.dup
|
15
|
+
node.inherit!
|
16
|
+
%i(validate_node).reduce(true) { |base, x| base && send(x, node) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def validate_node(node)
|
22
|
+
node.condition.each do |hash|
|
23
|
+
hash.symbolize_keys!
|
24
|
+
raise LintingError unless hash[:method]
|
25
|
+
Validators.validate!(filter: hash[:method], args: hash)
|
26
|
+
end
|
27
|
+
true
|
28
|
+
rescue Validators::ValidationError, LintingError
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def lint_nodes
|
33
|
+
CanCamel::Node.all.reduce(true) { |base, x| base && lint_node(x) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def lint_inheritance
|
37
|
+
CanCamel::Node.with_parents.where(<<-SQL).empty?
|
38
|
+
(
|
39
|
+
#{TABLE_NAME}.type = 'CanCamel::ActionNode'
|
40
|
+
AND
|
41
|
+
parents.type != 'CanCamel::SubjectNode'
|
42
|
+
)
|
43
|
+
OR
|
44
|
+
(
|
45
|
+
#{TABLE_NAME}.type = 'CanCamel::GroupNode'
|
46
|
+
AND
|
47
|
+
parents.type != 'CanCamel::ActionNode'
|
48
|
+
)
|
49
|
+
SQL
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module CanCamel
|
2
|
+
class Node < ActiveRecord::Base
|
3
|
+
self.table_name = TABLE_NAME
|
4
|
+
self.inheritance_column = 'type'
|
5
|
+
belongs_to :inherited_node, foreign_key: :inherit_id, class_name: "CanCamel::Node"
|
6
|
+
|
7
|
+
def self.with_parents
|
8
|
+
joins("LEFT JOIN #{TABLE_NAME} AS parents ON #{TABLE_NAME}.parent_id = parents.id")
|
9
|
+
end
|
10
|
+
|
11
|
+
def inherit!(source = nil)
|
12
|
+
return if inherited
|
13
|
+
@inherited = true
|
14
|
+
return inherit_source! source if source
|
15
|
+
|
16
|
+
inherit_source! parent if respond_to? :parent
|
17
|
+
inherit_source! inherited_node
|
18
|
+
end
|
19
|
+
|
20
|
+
validates! :inherited, absence: { message: "You should not save inherited nodes!" }
|
21
|
+
|
22
|
+
# accessors
|
23
|
+
|
24
|
+
def name
|
25
|
+
super.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :inherited
|
31
|
+
|
32
|
+
def inherit_source!(source)
|
33
|
+
return unless source
|
34
|
+
|
35
|
+
source.inherit!
|
36
|
+
|
37
|
+
inherit_field(source, :description) { |x| self.description ||= x }
|
38
|
+
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
|
46
|
+
end
|
47
|
+
|
48
|
+
def inherit_field(source, field)
|
49
|
+
return if override_fields.include?(field.to_s)
|
50
|
+
yield source.send(field)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module CanCamel::Validators
|
2
|
+
ValidationError = Class.new(StandardError)
|
3
|
+
UnknownFilter = Class.new(ValidationError)
|
4
|
+
|
5
|
+
class <<self
|
6
|
+
def included(base)
|
7
|
+
base.define_singleton_method(:validates) { |*args| CanCamel::Validators.validates *args }
|
8
|
+
end
|
9
|
+
|
10
|
+
def validates(filter, field = nil, **args)
|
11
|
+
validators[filter] ||= []
|
12
|
+
args.each do |key, value|
|
13
|
+
validator =
|
14
|
+
if field
|
15
|
+
-> (x) { send(key, field: x[field], **value) }
|
16
|
+
else
|
17
|
+
-> (x) { send(key, args: x, **value) }
|
18
|
+
end
|
19
|
+
validators[filter].push(validator)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def validate!(filter:, args:)
|
24
|
+
filter = filter.to_sym
|
25
|
+
unless validators[filter]
|
26
|
+
raise UnknownFilter unless CanCamel::Filters.respond_to? filter
|
27
|
+
return
|
28
|
+
end
|
29
|
+
validators[filter].each { |x| x.call(args) }
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def validators
|
35
|
+
@validators ||= {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def presence(field:)
|
39
|
+
raise ValidationError unless field.present?
|
40
|
+
end
|
41
|
+
|
42
|
+
def presence_of(fields:, args:, any: false)
|
43
|
+
condition = fields.map { |x| args[x].present? }.reduce { |base, x| any ? (base || x) : (base && x) }
|
44
|
+
return if condition
|
45
|
+
raise ValidationError
|
46
|
+
end
|
47
|
+
|
48
|
+
def in(field:, array: [], empty: false)
|
49
|
+
return if array.include? field
|
50
|
+
return if empty && !field.present?
|
51
|
+
raise ValidationError
|
52
|
+
end
|
53
|
+
|
54
|
+
def custom(field:, lambda:, empty: false)
|
55
|
+
return if empty && !field.present?
|
56
|
+
return if lambda.call(field)
|
57
|
+
raise ValidationError
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateCanCamelNodes < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
reversible do |d|
|
4
|
+
d.up { execute 'CREATE extension IF NOT EXISTS hstore;' }
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table CanCamel::TABLE_NAME do |t|
|
8
|
+
t.column :name, :string, index: true
|
9
|
+
t.column :description, :text, null: true
|
10
|
+
t.column :parent_id, :integer, null: true
|
11
|
+
t.column :inherit_id, :integer, null: true
|
12
|
+
t.column :type, :string
|
13
|
+
t.column :override_fields, :string, array: true, default: []
|
14
|
+
t.column :condition, :hstore, array: true, default: []
|
15
|
+
t.column :result, :hstore, default: {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class CanCamel::InstallGenerator < Rails::Generators::Base
|
2
|
+
desc "Generates initializer and some migrations"
|
3
|
+
source_root(File.expand_path("..", __FILE__))
|
4
|
+
def install
|
5
|
+
copy_file 'config/initializers/can_camel.rb'
|
6
|
+
copy_file 'db/migrate/00000000000001_create_can_camel_nodes.rb'
|
7
|
+
end
|
8
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: can_camel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Smirnov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pg
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: |2
|
42
|
+
CanCamel allows to manage access levels with all the power of cancan style (saving semantics). It means, that you can use `can?` method anywhere you want to check privileges of a selected user to access something in some way. See readme file at https://github.com/JelF/can_camel/blob/master/README.md to learn more
|
43
|
+
email:
|
44
|
+
- begdory4@gmail.com
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- LICENSE
|
50
|
+
- Rakefile
|
51
|
+
- lib/can_camel.rb
|
52
|
+
- lib/can_camel/action_node.rb
|
53
|
+
- lib/can_camel/base.rb
|
54
|
+
- lib/can_camel/cache.rb
|
55
|
+
- lib/can_camel/concern_node.rb
|
56
|
+
- lib/can_camel/filter_helper.rb
|
57
|
+
- lib/can_camel/filters.rb
|
58
|
+
- lib/can_camel/group_node.rb
|
59
|
+
- lib/can_camel/linter.rb
|
60
|
+
- lib/can_camel/node.rb
|
61
|
+
- lib/can_camel/subject_node.rb
|
62
|
+
- lib/can_camel/validators.rb
|
63
|
+
- lib/can_camel/version.rb
|
64
|
+
- lib/generators/can_camel/config/initializers/can_camel.rb
|
65
|
+
- lib/generators/can_camel/db/migrate/00000000000001_create_can_camel_nodes.rb
|
66
|
+
- lib/generators/can_camel/install_generator.rb
|
67
|
+
- lib/tasks/can_camel_tasks.rake
|
68
|
+
homepage: https://github.com/JelF/can_camel
|
69
|
+
licenses:
|
70
|
+
- WTFPL
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.4.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: CanCamel is a cancan style access controll library
|
92
|
+
test_files: []
|