can_camel 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,8 @@
1
+ module CanCamel
2
+ extend ActiveSupport::Autoload
3
+ %i(Base Node SubjectNode ActionNode GroupNode ConcernNode Linter Filters
4
+ Validators Cache FilterHelper)
5
+ .each { |x| autoload(x) }
6
+
7
+ extend CanCamel::Base
8
+ end
@@ -0,0 +1,8 @@
1
+ module CanCamel
2
+ class ActionNode < Node
3
+ has_many :groups, foreign_key: :parent_id, class_name: "CanCamel::GroupNode"
4
+ belongs_to :parent, foreign_key: :parent_id, class_name: "CanCamel::SubjectNode"
5
+
6
+ validates_presence_of :parent_id
7
+ end
8
+ end
@@ -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,5 @@
1
+ module CanCamel
2
+ class ConcernNode < Node
3
+ validates :parent_id, absence: true
4
+ end
5
+ 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,7 @@
1
+ module CanCamel
2
+ class SubjectNode < Node
3
+ has_many :actions, foreign_key: :parent_id, class_name: "CanCamel::ActionNode"
4
+
5
+ validates :parent_id, absence: true
6
+ end
7
+ 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,3 @@
1
+ module CanCamel
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ # include custom ability filters
2
+ # require 'can_camel/filters'
3
+ # CanCamel::Filters.include AbilityFilters
4
+ CanCamel::TABLE_NAME = "can_camel_nodes"
@@ -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
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :can_camel do
3
+ # # Task goes here
4
+ # 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: []