i_am_i_can 3.0.1 → 4.0.0
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/.gitignore +1 -0
- data/README.md +236 -174
- data/lib/generators/i_am_i_can/setup_generator.rb +3 -7
- data/lib/generators/i_am_i_can/templates/migrations/i_am_i_can.erb +8 -8
- data/lib/generators/i_am_i_can/templates/models/permission.erb +4 -2
- data/lib/generators/i_am_i_can/templates/models/role.erb +3 -1
- data/lib/generators/i_am_i_can/templates/models/role_group.erb +3 -1
- data/lib/i_am_i_can/configs/config.rb +2 -3
- data/lib/i_am_i_can/configs/configs.rb +1 -7
- data/lib/i_am_i_can/helpers/dynamic.rb +102 -0
- data/lib/i_am_i_can/helpers/result_of.rb +71 -0
- data/lib/i_am_i_can/permission/assignment.rb +12 -60
- data/lib/i_am_i_can/permission/definition.rb +8 -28
- data/lib/i_am_i_can/permission.rb +18 -24
- data/lib/i_am_i_can/resource.rb +24 -19
- data/lib/i_am_i_can/role/assignment.rb +24 -45
- data/lib/i_am_i_can/role/definition.rb +17 -47
- data/lib/i_am_i_can/role.rb +14 -0
- data/lib/i_am_i_can/role_group/assignment.rb +6 -0
- data/lib/i_am_i_can/role_group/definition.rb +25 -0
- data/lib/i_am_i_can/subject/permission_querying.rb +28 -40
- data/lib/i_am_i_can/subject/role_querying.rb +8 -8
- data/lib/i_am_i_can/subject.rb +0 -10
- data/lib/i_am_i_can/support/association_class_methods.rb +43 -0
- data/lib/i_am_i_can/{configurable.rb → support/configurable.rb} +0 -7
- data/lib/i_am_i_can/support/reflection.rb +36 -0
- data/lib/i_am_i_can/version.rb +1 -1
- data/lib/i_am_i_can.rb +33 -16
- metadata +9 -9
- data/Gemfile.lock +0 -121
- data/lib/i_am_i_can/dynamic_generate.rb +0 -95
- data/lib/i_am_i_can/permission/helpers.rb +0 -75
- data/lib/i_am_i_can/permission/p_array.rb +0 -22
- data/lib/i_am_i_can/reflection.rb +0 -25
- data/lib/i_am_i_can/role/helpers.rb +0 -76
@@ -5,14 +5,16 @@ class <%= permission_c %> < ActiveRecord::Base
|
|
5
5
|
has_and_belongs_to_many :related_role_groups,
|
6
6
|
join_table: '<%= group_pms_tb %>', foreign_key: :<%= group_u %>_id, class_name: '<%= group_c %>', association_foreign_key: :<%= permission_u %>_id
|
7
7
|
<% end %>
|
8
|
+
belongs_to :obj, polymorphic: true
|
9
|
+
|
8
10
|
acts_as_permission
|
9
11
|
end
|
10
12
|
|
11
13
|
__END__
|
12
14
|
|
13
|
-
string :
|
15
|
+
string :action, null: false
|
14
16
|
string :obj_type
|
15
17
|
integer :obj_id
|
16
18
|
string :desc
|
17
19
|
|
18
|
-
index %i[
|
20
|
+
index %i[ action obj_type obj_id ], unique: true
|
@@ -5,9 +5,11 @@ class <%= role_c %> < ActiveRecord::Base
|
|
5
5
|
has_and_belongs_to_many :related_stored_groups,
|
6
6
|
join_table: '<%= group_role_tb %>', foreign_key: :<%= group_u %>_id, class_name: '<%= group_c %>', association_foreign_key: :<%= role_u %>_id
|
7
7
|
<% end %>
|
8
|
-
has_and_belongs_to_many :
|
8
|
+
has_and_belongs_to_many :permissions,
|
9
9
|
join_table: '<%= role_pms_tb %>', foreign_key: :<%= permission_u %>_id, class_name: '<%= permission_c %>', association_foreign_key: :<%= role_u %>_id
|
10
10
|
|
11
|
+
has_many_temporary_permissions
|
12
|
+
|
11
13
|
acts_as_role
|
12
14
|
|
13
15
|
# default_scope { with_stored_permissions }
|
@@ -1,10 +1,12 @@
|
|
1
1
|
class RoleGroup < ActiveRecord::Base
|
2
|
-
has_and_belongs_to_many :
|
2
|
+
has_and_belongs_to_many :permissions,
|
3
3
|
join_table: '<%= group_pms_tb %>', foreign_key: :<%= permission_u %>_id, class_name: '<%= permission_c %>', association_foreign_key: :<%= group_u %>_id
|
4
4
|
|
5
5
|
has_and_belongs_to_many :members,
|
6
6
|
join_table: '<%= group_role_tb %>', foreign_key: :<%= role_u %>_id, class_name: '<%= role_c %>', association_foreign_key: :<%= group_u %>_id
|
7
7
|
|
8
|
+
has_many_temporary_permissions
|
9
|
+
|
8
10
|
acts_as_role_group
|
9
11
|
|
10
12
|
# default_scope { with_members.with_stored_permissions) }
|
@@ -2,14 +2,13 @@ module IAmICan
|
|
2
2
|
module Configs
|
3
3
|
class Config
|
4
4
|
attr_accessor :subject_class, :role_class, :role_group_class, :permission_class,
|
5
|
-
:
|
5
|
+
:auto_definition, :strict_mode, :without_group, :act
|
6
6
|
|
7
7
|
def initialize(*classes)
|
8
8
|
self.subject_class, self.role_class, self.permission_class, self.role_group_class = classes
|
9
|
-
self.
|
9
|
+
self.auto_definition = false
|
10
10
|
self.strict_mode = false
|
11
11
|
self.without_group = false
|
12
|
-
self.default_save = true
|
13
12
|
end
|
14
13
|
|
15
14
|
def subject_model
|
@@ -2,9 +2,7 @@ require 'i_am_i_can/configs/config'
|
|
2
2
|
|
3
3
|
module IAmICan
|
4
4
|
module Configs
|
5
|
-
cattr_accessor :configs
|
6
|
-
{ }
|
7
|
-
end
|
5
|
+
cattr_accessor :configs, default: { }
|
8
6
|
|
9
7
|
def self.set_for(subject:, role:, permission:, role_group: nil, &block)
|
10
8
|
config = Config.new(subject, role, permission, role_group)
|
@@ -21,9 +19,5 @@ module IAmICan
|
|
21
19
|
def self.get(class_name)
|
22
20
|
configs[class_name]
|
23
21
|
end
|
24
|
-
|
25
|
-
def self.take
|
26
|
-
configs.values.first
|
27
|
-
end
|
28
22
|
end
|
29
23
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module IAmICan
|
2
|
+
module Dynamic
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def scopes
|
6
|
+
#
|
7
|
+
# Generate scopes of each specified i_am_i_can association
|
8
|
+
#
|
9
|
+
# scope :with_stored_roles, -> { includes(:stored_roles) }
|
10
|
+
#
|
11
|
+
proc do |keys|
|
12
|
+
keys.each do |k|
|
13
|
+
scope :"with_#{_reflect_of(k)}", -> { includes(_reflect_of(k)) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def class_reflections
|
19
|
+
#
|
20
|
+
# Extend each associated querying to a class method that returns ActiveRecord::Relation
|
21
|
+
#
|
22
|
+
# Suppose: in UserRole model,
|
23
|
+
# has_and_belongs_to_many :related_users
|
24
|
+
#
|
25
|
+
# It will do like this:
|
26
|
+
# def self.related_users
|
27
|
+
# User.with_stored_roles.where(user_roles: { id: self.ids })
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Usage:
|
31
|
+
# UserRole.all.related_users
|
32
|
+
#
|
33
|
+
proc do
|
34
|
+
%w[ subject role role_group permission ].each do |k|
|
35
|
+
next if _reflect_of(k).blank?
|
36
|
+
define_singleton_method _reflect_of(k) do
|
37
|
+
model = i_am_i_can.send("#{k}_model")
|
38
|
+
raise NoMethodError unless (reflect_name = model._reflect_of(i_am_i_can.act))
|
39
|
+
|
40
|
+
model.send("with_#{reflect_name}").where(
|
41
|
+
self.name.underscore.pluralize => { id: self.ids }
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def assignment_helpers
|
49
|
+
#
|
50
|
+
# Generate methods for each Content of Assignment
|
51
|
+
#
|
52
|
+
# Example for a subject model called User, which `has_and_belongs_to_many :stored_roles`.
|
53
|
+
# You call the proc below by given contents [:role], then:
|
54
|
+
#
|
55
|
+
proc { |contents| contents.each do |content|
|
56
|
+
content_cls = i_am_i_can.send("#{content}_class")
|
57
|
+
_plural = '_' + content.to_s.pluralize
|
58
|
+
|
59
|
+
# _stored_roles_exec
|
60
|
+
# Add / Remove (by passing action :cancel) roles to a user instance
|
61
|
+
define_method "_#{_reflect_of(content)}_exec" do |action = :assignment, instances = [ ], **conditions|
|
62
|
+
collection = send(_plural)
|
63
|
+
if conditions.present? && action == :assignment
|
64
|
+
# Role.where(name: [...]).where.not(id: roles.ids)
|
65
|
+
query_result = content_cls.constantize.where(conditions).where.not(id: collection.ids)
|
66
|
+
elsif conditions.present? && action == :cancel
|
67
|
+
# Role.where(id: roles.ids, name: [...])
|
68
|
+
query_result = content_cls.constantize.where(id: collection.ids, **conditions)
|
69
|
+
end
|
70
|
+
|
71
|
+
objects = [*(query_result || [ ]), *(instances - collection)].uniq
|
72
|
+
action == :assignment ? collection << objects : collection.destroy(objects)
|
73
|
+
objects
|
74
|
+
end
|
75
|
+
#
|
76
|
+
alias_method "_stored#{_plural}_exec", "_#{_reflect_of(content)}_exec"
|
77
|
+
end }
|
78
|
+
end
|
79
|
+
|
80
|
+
def definition_helpers
|
81
|
+
#
|
82
|
+
# Generate class methods for each Content of Definition
|
83
|
+
#
|
84
|
+
# Example for a subject model called User,
|
85
|
+
# which `has_many_temporary_roles` and `has_and_belongs_to_many :stored_roles`.
|
86
|
+
# You call the proc below by given contents [:role], then:
|
87
|
+
#
|
88
|
+
proc { |contents| contents.each do |content|
|
89
|
+
content_cls = i_am_i_can.send("#{content}_class")
|
90
|
+
_plural = '_' + content.to_s.pluralize
|
91
|
+
|
92
|
+
# _create_roles
|
93
|
+
# Define and store roles of Subject
|
94
|
+
define_singleton_method "_create#{_plural}" do |objects|
|
95
|
+
# Role.create([{ name: .. }]).reject { the roles that validation failed }
|
96
|
+
content_cls.constantize.create(objects)
|
97
|
+
.reject {|record| record.new_record? }
|
98
|
+
end
|
99
|
+
end }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module IAmICan
|
2
|
+
module ResultOf
|
3
|
+
module Role
|
4
|
+
def roles definition, i_am_i_can, given: [ ]
|
5
|
+
ResultOf.(definition, [ [], given ], config: i_am_i_can,
|
6
|
+
msg_prefix: 'Role Definition: ',
|
7
|
+
fail_msg: 'have been used by other roles!'
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def role assignment, i_am_i_can, given: [ ]
|
12
|
+
ResultOf.(assignment, given, config: i_am_i_can,
|
13
|
+
msg_prefix: 'Role Assignment: ',
|
14
|
+
fail_msg: 'have not been defined or have been repeatedly assigned!'
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
ResultOf.include self
|
19
|
+
end
|
20
|
+
|
21
|
+
module RoleGroup
|
22
|
+
def members assignment, i_am_i_can, given: [ ]
|
23
|
+
ResultOf.(assignment, given, config: i_am_i_can,
|
24
|
+
msg_prefix: 'Role Grouping: ',
|
25
|
+
fail_msg: 'have not been defined!'
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
ResultOf.include self
|
30
|
+
end
|
31
|
+
|
32
|
+
module Permission
|
33
|
+
def permissions definition, i_am_i_can, given: [ ]
|
34
|
+
ResultOf.(definition, [ [], given ], config: i_am_i_can,
|
35
|
+
msg_prefix: 'Permission Definition: ',
|
36
|
+
fail_msg: 'have been used by other permissions!'
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def permission assignment, i_am_i_can, given: [ ]
|
41
|
+
ResultOf.(assignment, given, config: i_am_i_can,
|
42
|
+
msg_prefix: 'Permission Assignment: ',
|
43
|
+
fail_msg: 'have not been defined or have been repeatedly assigned!'
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
ResultOf.include self
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(assignment, given, msg_prefix:, fail_msg:, config:)
|
51
|
+
instances, names = given
|
52
|
+
instances.map!(&:name).map!(&:to_sym)
|
53
|
+
assignment = assignment.map(&:name).map(&:to_sym) unless assignment.first.is_a?(Symbol)
|
54
|
+
|
55
|
+
to_be_assigned_names = (instances + names).uniq
|
56
|
+
failed_items = to_be_assigned_names - assignment
|
57
|
+
|
58
|
+
msg = msg_prefix + (assignment.blank? ? 'do nothing' : "#{assignment} DONE")
|
59
|
+
msg << "; And #{failed_items} #{fail_msg}" if failed_items.present?
|
60
|
+
|
61
|
+
if config.strict_mode && failed_items.present?
|
62
|
+
raise Error, msg
|
63
|
+
else
|
64
|
+
Rails.logger.info(msg) unless ENV['ITEST']
|
65
|
+
assignment
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
extend self
|
70
|
+
end
|
71
|
+
end
|
@@ -1,75 +1,27 @@
|
|
1
|
-
require 'i_am_i_can/permission/helpers'
|
2
|
-
|
3
1
|
module IAmICan
|
4
2
|
module Permission
|
5
3
|
module Assignment
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
not_defined_items, covered_items = [ ], [ ]
|
12
|
-
|
13
|
-
preds.each do |pred|
|
14
|
-
pms_name = pms_naming(pred, obj)
|
15
|
-
covered_items << pms_name if pms_matched?(pms_name, in: stored_permission_names)
|
16
|
-
not_defined_items << pms_name unless stored_permissions_add(pred: pred, **deconstruct_obj(obj))
|
17
|
-
end
|
18
|
-
|
19
|
-
_pms_assignment_result(preds, obj, not_defined_items, covered_items, strict_mode)
|
4
|
+
def can *actions,
|
5
|
+
resource: nil, obj: resource,
|
6
|
+
_d: i_am_i_can.auto_definition, auto_definition: _d
|
7
|
+
self.class.have_permissions *actions, obj: obj if auto_definition
|
8
|
+
_permissions_assignment(actions, obj)
|
20
9
|
end
|
21
10
|
|
22
11
|
alias has_permission can
|
23
12
|
|
24
|
-
def
|
25
|
-
|
26
|
-
self.class.have_permissions *preds, obj: obj, save: false if auto_define_before
|
27
|
-
not_defined_items, covered_items = [ ], [ ]
|
28
|
-
|
29
|
-
preds.each do |pred|
|
30
|
-
pms_name = pms_naming(pred, obj)
|
31
|
-
next not_defined_items << pms_name unless pms_name.in?(defined_permissions.keys)
|
32
|
-
covered_items << pms_name if pms_matched?(pms_name, in: pms_of_defined_local_role(self.name))
|
33
|
-
pms_of_defined_local_role(self.name) << pms_name
|
34
|
-
end
|
35
|
-
|
36
|
-
_pms_assignment_result(preds, obj, not_defined_items, covered_items, strict_mode)
|
37
|
-
end
|
38
|
-
|
39
|
-
alias locally_can temporarily_can
|
40
|
-
|
41
|
-
def cannot *preds, obj: nil, saved: true
|
42
|
-
not_defined_items = [ ]
|
43
|
-
|
44
|
-
preds.each do |pred|
|
45
|
-
pms_name = pms_naming(pred, obj)
|
46
|
-
if saved
|
47
|
-
next if stored_permissions_rmv(pred: pred, **deconstruct_obj(obj))
|
48
|
-
not_defined_items << pms_name
|
49
|
-
else
|
50
|
-
next not_defined_items << pms_name unless pms_name.in?(defined_permissions.keys)
|
51
|
-
pms_of_defined_local_role(self.name).delete(pms_name)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
_pms_assignment_result(preds, obj, not_defined_items)
|
13
|
+
def cannot *actions, obj: nil
|
14
|
+
_permissions_assignment(:cancel, actions, obj)
|
56
15
|
end
|
57
16
|
|
58
17
|
alias is_not_allowed_to cannot
|
59
18
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
19
|
+
def _permissions_assignment(action = :assignment, actions, obj)
|
20
|
+
permissions = actions.product(Array[obj]).map { |(p, o)| { action: p, **deconstruct_obj(o) } }
|
21
|
+
assignment = _stored_permissions_exec(action,
|
22
|
+
permissions.reduce({ }) { |a, b| a.merge(b) { |_, x, y| [x, y] } })
|
23
|
+
ResultOf.permission assignment, i_am_i_can, given: [[], permissions.map { |pms| pms.values.compact.join('_').to_sym }]
|
65
24
|
end
|
66
|
-
|
67
|
-
def temporarily_can? pred, obj
|
68
|
-
pms_name = pms_naming(pred, obj)
|
69
|
-
pms_matched?(pms_name, in: pms_of_defined_local_role(self.name))
|
70
|
-
end
|
71
|
-
|
72
|
-
alias locally_can? temporarily_can?
|
73
25
|
end
|
74
26
|
end
|
75
27
|
end
|
@@ -1,40 +1,20 @@
|
|
1
|
-
require 'i_am_i_can/permission/helpers'
|
2
|
-
require 'i_am_i_can/permission/p_array'
|
3
|
-
|
4
1
|
module IAmICan
|
5
2
|
module Permission
|
6
3
|
module Definition
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
preds.each do |pred|
|
13
|
-
pms_name = pms_naming(pred, obj)
|
14
|
-
description = desc || pms_name.to_s.tr('_', ' ')
|
15
|
-
if save
|
16
|
-
failed_items << pms_name unless _to_store_permission(pred, obj, desc: description)
|
17
|
-
else
|
18
|
-
failed_items << pms_name if pms_name.in?(defined_local_permissions.keys)
|
19
|
-
defined_local_permissions[pms_name] ||= { desc: description }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
_pms_definition_result(preds, obj, failed_items)
|
4
|
+
def have_permission *actions, obj: nil
|
5
|
+
permissions = actions.product(Array[obj]).map { |(p, o)| { action: p, **deconstruct_obj(o) } }
|
6
|
+
definition = _create_permissions(permissions)
|
7
|
+
ResultOf.roles definition, i_am_i_can, given: permissions.map { |pms| pms.values.compact.join('_').to_sym }
|
24
8
|
end
|
25
9
|
|
26
|
-
|
27
|
-
alias has_permission have_permission
|
28
|
-
alias has_permissions have_permission
|
10
|
+
%i[ have_permissions has_permission has_permissions ].each { |aname| alias_method aname, :have_permission }
|
29
11
|
|
30
|
-
def
|
31
|
-
|
12
|
+
def deconstruct_obj(obj)
|
13
|
+
i_am_i_can.permission_model.deconstruct_obj(obj)
|
32
14
|
end
|
33
15
|
|
34
|
-
alias declare_permissions declare_permission
|
35
|
-
|
36
16
|
def self.extended(kls)
|
37
|
-
kls.delegate :
|
17
|
+
kls.delegate :deconstruct_obj, to: kls
|
38
18
|
end
|
39
19
|
end
|
40
20
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'i_am_i_can/permission/p_array'
|
2
1
|
require 'i_am_i_can/permission/definition'
|
3
2
|
require 'i_am_i_can/permission/assignment'
|
4
3
|
|
@@ -7,19 +6,23 @@ module IAmICan
|
|
7
6
|
extend ActiveSupport::Concern
|
8
7
|
|
9
8
|
class_methods do
|
10
|
-
def matched
|
11
|
-
|
9
|
+
def matched(actions, obj)
|
10
|
+
_ = deconstruct_obj(obj)
|
11
|
+
where(action: actions,
|
12
|
+
obj_type: [nil, _[:obj_type]],
|
13
|
+
obj_id: [nil, _[:obj_id]])
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
15
|
-
|
16
|
+
def matched?(actions, obj)
|
17
|
+
matched(actions, obj).present?
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def matched_all?(actions, obj)
|
21
|
+
matched(actions, obj).count == Array(actions).count
|
22
|
+
end
|
23
|
+
|
24
|
+
def which(action:, obj: nil, **conditions)
|
25
|
+
find_by!(action: action, **deconstruct_obj(obj), **conditions)
|
23
26
|
end
|
24
27
|
|
25
28
|
def deconstruct_obj(obj)
|
@@ -34,32 +37,23 @@ module IAmICan
|
|
34
37
|
end
|
35
38
|
end
|
36
39
|
|
37
|
-
def
|
38
|
-
|
40
|
+
def names
|
41
|
+
all.map(&:name)
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
42
45
|
included do
|
43
46
|
# like: manage_User_1
|
44
47
|
def name
|
45
|
-
|
46
|
-
oid = "_#{obj_id}" if obj_id.present?
|
47
|
-
[pred, otp, oid].join.to_sym
|
48
|
+
[action, obj_type, obj_id].compact.join('_').to_sym
|
48
49
|
end
|
49
50
|
|
50
51
|
# def assign_to role: nil, group: nil
|
51
|
-
# obj = if role
|
52
|
-
# role.is_a?(Symbol) ? i_am_i_can.role_model.find(name: role) : role
|
53
|
-
# else
|
54
|
-
# group.is_a?(Symbol) ? i_am_i_can.role_group_model.find(name: role) : group
|
55
|
-
# end
|
56
|
-
# obj.have_permission self.pred, obj: self.obj
|
57
52
|
# end
|
58
|
-
#
|
59
|
-
# alias is_assigned_to assign_to
|
60
53
|
|
61
|
-
# :user, User, user
|
54
|
+
# returns :user, User, user
|
62
55
|
def obj
|
56
|
+
return if obj_type.blank?
|
63
57
|
return obj_type.constantize.find(obj_id) if obj_id.present?
|
64
58
|
obj_type[/[A-Z]/] ? obj_type.constantize : obj_type.to_sym
|
65
59
|
end
|
data/lib/i_am_i_can/resource.rb
CHANGED
@@ -2,28 +2,33 @@ module IAmICan
|
|
2
2
|
module Resource
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
|
6
|
-
# Book.that_allow(User.all
|
7
|
-
# Book.that_allow(User.last
|
8
|
-
|
9
|
-
|
5
|
+
included do
|
6
|
+
# Book.that_allow(User.all, to: :read)
|
7
|
+
# Book.that_allow(User.last, to: :write)
|
8
|
+
scope :that_allow, -> (subject, to:) do
|
9
|
+
tmp_role_ids = Array(subject).flat_map(&:temporary_roles).map(&:id).uniq
|
10
|
+
allowed_ids = subject.i_am_i_can.role_model.where(id: (subject._roles.ids + tmp_role_ids).uniq)
|
11
|
+
._permissions.where(action: to, obj_type: self.name).pluck(:obj_id).uniq
|
12
|
+
where(id: allowed_ids)
|
10
13
|
end
|
11
14
|
end
|
12
|
-
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
self.records = records
|
19
|
-
self.subject = subject
|
20
|
-
end
|
21
|
-
|
22
|
-
def to(pred)
|
23
|
-
roles = Configs.take.subject_model._roles
|
24
|
-
permissions = Configs.take.role_model._permissions
|
25
|
-
allowed_ids = subject.send(roles).send(permissions).where(pred: pred, obj_type: records.name).pluck(:obj_id).uniq
|
26
|
-
records.where(id: allowed_ids)
|
16
|
+
class_methods do
|
17
|
+
# def that_allow(subject)
|
18
|
+
# ThatAllow.new(self, subject)
|
19
|
+
# end
|
27
20
|
end
|
28
21
|
end
|
22
|
+
|
23
|
+
# class ThatAllow
|
24
|
+
# attr_accessor :records, :subject
|
25
|
+
#
|
26
|
+
# def initialize(records, subject)
|
27
|
+
# self.records = records
|
28
|
+
# self.subject = subject
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def to(action)
|
32
|
+
# end
|
33
|
+
# end
|
29
34
|
end
|
@@ -1,62 +1,41 @@
|
|
1
|
-
require 'i_am_i_can/role/helpers'
|
2
|
-
|
3
1
|
module IAmICan
|
4
2
|
module Role
|
5
3
|
module Assignment
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
self.class.have_roles *roles, which_can: which_can, obj: obj
|
11
|
-
|
12
|
-
|
13
|
-
roles.map(&__role).each do |role|
|
14
|
-
if save
|
15
|
-
failed_items << role unless stored_roles_add(role)
|
16
|
-
else
|
17
|
-
next failed_items << role unless role.in?(defined_roles.keys)
|
18
|
-
local_role_names << role unless role.in?(local_role_names)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
_role_assignment_result(roles, failed_items)
|
4
|
+
def becomes_a *roles, which_can: [ ], obj: nil,
|
5
|
+
_d: i_am_i_can.auto_definition,
|
6
|
+
auto_definition: _d || which_can.present?,
|
7
|
+
save: true
|
8
|
+
self.class.have_roles *roles, which_can: which_can, obj: obj if auto_definition
|
9
|
+
_roles_assignment(roles, save)
|
23
10
|
end
|
24
11
|
|
25
|
-
|
26
|
-
alias is_a_role becomes_a
|
27
|
-
alias is_roles becomes_a
|
28
|
-
alias has_role becomes_a
|
29
|
-
alias has_roles becomes_a
|
30
|
-
alias role_is becomes_a
|
31
|
-
alias roles_are becomes_a
|
12
|
+
%i[ is is_a is_a_role is_roles has_role has_roles role_is role_are ].each { |aname| alias_method aname, :becomes_a }
|
32
13
|
|
33
|
-
def
|
14
|
+
def is_a_temporary *roles, **options
|
34
15
|
becomes_a *roles, save: false, **options
|
35
16
|
end
|
36
17
|
|
37
|
-
|
18
|
+
def falls_from *roles, saved: true
|
19
|
+
_roles_assignment(:cancel, roles, saved)
|
20
|
+
end
|
21
|
+
|
22
|
+
%i[ is_not_a will_not_be removes_role leaves has_not_role has_not_roles ].each { |aname| alias_method aname, :falls_from }
|
38
23
|
|
39
|
-
def
|
40
|
-
|
24
|
+
def is_not_a_temporary *roles
|
25
|
+
falls_from *roles, saved: false
|
26
|
+
end
|
41
27
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
28
|
+
def _roles_assignment(action = :assignment, roles, save)
|
29
|
+
instances, names = Role.extract(roles, i_am_i_can)
|
30
|
+
if save
|
31
|
+
assignment = _stored_roles_exec(action, instances, name: names)
|
32
|
+
else
|
33
|
+
to_be_assigned_names = (instances.map(&:name).map(&:to_sym) + names).uniq
|
34
|
+
assignment = _temporary_roles_exec(action, to_be_assigned_names)
|
49
35
|
end
|
50
36
|
|
51
|
-
|
37
|
+
ResultOf.role assignment, i_am_i_can, given: [instances, names]
|
52
38
|
end
|
53
|
-
|
54
|
-
alias is_not_a falls_from
|
55
|
-
alias will_not_be falls_from
|
56
|
-
alias removes_role falls_from
|
57
|
-
alias leaves falls_from
|
58
|
-
alias has_not_role falls_from
|
59
|
-
alias has_not_roles falls_from
|
60
39
|
end
|
61
40
|
end
|
62
41
|
end
|