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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19f8ade41da75b5b9b3beb17bc729b62fae529e3
4
- data.tar.gz: 44fd15e4109320bc9143dd4acb992bed642955b3
3
+ metadata.gz: 6cd2a7e24ff8c42df996b7255ecfc0710ae5b011
4
+ data.tar.gz: 97d7813911fdbbcc34c765243df8f047fceef026
5
5
  SHA512:
6
- metadata.gz: f02195d10717ac041a2e64df9b893d8f2d14a91051bdaa87a3b5e4cc668dda8f4e8dc932744330d982905e8a2b216fbebc7ec7d033b02549dd3287b88e6638c2
7
- data.tar.gz: 590a5bd7ec97794d11638630d45561b496f3279428ab8dadb83078b12b65437d6ca859de64694fe0a3ce30c7b2c6a869116f6f5c0de87bdd1e607e4b76878504
6
+ metadata.gz: 89e48cc509dfe2269a5f308e3234fbcbe2400642b22c916b44937b72f32fcbfb57eaa28de6d4162b23e4d69f37cd4a6a222ca79270994faf6a29d0ff01ba5338
7
+ data.tar.gz: c765a6da93ea8aa404105b405a22a8598348a5c4a42b54c36655f6c471c61d46228eeb3c077962f88c933457aa4a641ec09e641dc4d3fd3d4faf16e1b86e18e2
@@ -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
@@ -1,7 +1,7 @@
1
1
  module CanCamel
2
2
  extend ActiveSupport::Autoload
3
3
  %i(Base Node SubjectNode ActionNode GroupNode ConcernNode Linter Filters
4
- Validators Cache FilterHelper)
4
+ Validators Cache)
5
5
  .each { |x| autoload(x) }
6
6
 
7
7
  extend CanCamel::Base
@@ -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?(group, action, subject, **args)
7
- Cache[[group, action, subject]].try(:can?, args)
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
@@ -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 && !from_int_array(days).include?(Time.now.day)
18
- return if wdays && !from_int_array(wdays).include?(Time.now.wday)
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
@@ -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 |hash, result|
9
- hash.symbolize_keys!
10
- raise Linter::LintingError unless hash[:method]
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
@@ -19,10 +19,8 @@ module CanCamel
19
19
  private
20
20
 
21
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)
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
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module CanCamel
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -2,3 +2,4 @@
2
2
  # require 'can_camel/filters'
3
3
  # CanCamel::Filters.include AbilityFilters
4
4
  CanCamel::TABLE_NAME = "can_camel_nodes"
5
+ CanCamel::GROUP_METHOD = :group
@@ -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
@@ -4,5 +4,6 @@ class CanCamel::InstallGenerator < Rails::Generators::Base
4
4
  def install
5
5
  copy_file 'config/initializers/can_camel.rb'
6
6
  copy_file 'db/migrate/00000000000001_create_can_camel_nodes.rb'
7
+ copy_file 'db/migrate/00000000000002_hstore_to_json.rb'
7
8
  end
8
9
  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.0
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-08 00:00:00.000000000 Z
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.0
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.0
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: '0'
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