monarchy 0.3.1 → 1.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/Gemfile +1 -0
- data/Gemfile.lock +48 -43
- data/app/models/monarchy/member.rb +4 -0
- data/app/models/monarchy/members_role.rb +9 -0
- data/app/models/monarchy/role.rb +4 -0
- data/lib/generators/monarchy/setup_generator.rb +0 -3
- data/lib/generators/templates/config.rb +7 -0
- data/lib/generators/templates/migrations/membership.rb +14 -2
- data/lib/monarchy/acts_as_hierarchy.rb +25 -6
- data/lib/monarchy/acts_as_member.rb +82 -0
- data/lib/monarchy/acts_as_resource.rb +18 -13
- data/lib/monarchy/acts_as_role.rb +31 -0
- data/lib/monarchy/acts_as_user.rb +35 -24
- data/lib/monarchy/version.rb +1 -1
- data/lib/monarchy.rb +29 -2
- data/lib/tasks/monarchy_tasks.rake +17 -4
- data/monarchy.gemspec +1 -0
- metadata +21 -6
- data/lib/generators/templates/migrations/user.rb +0 -7
- data/lib/generators/templates/models/hierarchy.rb +0 -4
- data/lib/generators/templates/models/user.rb +0 -3
- data/lib/monarchy/membership.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7dfc2d0fdc01fa14cb113bb0d1cf87533af6e849
|
4
|
+
data.tar.gz: 6ca7712af3dfbe53c0f309432415471bb1f70cf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: defd04040f7ece731b35b84ee04000f72cb08be7cceef9d63ba043d61b77459e8a11cdee5f15cbdcece69f1898ce3709c3e127816040159997bf49a96be01a16
|
7
|
+
data.tar.gz: fb7b2313b86d63b912b8741038fe245dbf6847ecccce9d681db5575ba370a7f1661bbc5658c6fdeadbdbc650e23e08c809c89db894f49a5a17e51a8247f9ee94
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,54 +1,55 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
monarchy (0.3.
|
4
|
+
monarchy (0.3.1)
|
5
5
|
active_record_union (= 1.1.1)
|
6
6
|
closure_tree (= 6.0.0)
|
7
7
|
configurations (= 2.2.0)
|
8
8
|
rails (~> 4.2, >= 4.2.4)
|
9
|
+
tqdm (= 0.3.0)
|
9
10
|
|
10
11
|
GEM
|
11
12
|
remote: https://rubygems.org/
|
12
13
|
specs:
|
13
|
-
actionmailer (4.2.
|
14
|
-
actionpack (= 4.2.
|
15
|
-
actionview (= 4.2.
|
16
|
-
activejob (= 4.2.
|
14
|
+
actionmailer (4.2.7)
|
15
|
+
actionpack (= 4.2.7)
|
16
|
+
actionview (= 4.2.7)
|
17
|
+
activejob (= 4.2.7)
|
17
18
|
mail (~> 2.5, >= 2.5.4)
|
18
19
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
19
|
-
actionpack (4.2.
|
20
|
-
actionview (= 4.2.
|
21
|
-
activesupport (= 4.2.
|
20
|
+
actionpack (4.2.7)
|
21
|
+
actionview (= 4.2.7)
|
22
|
+
activesupport (= 4.2.7)
|
22
23
|
rack (~> 1.6)
|
23
24
|
rack-test (~> 0.6.2)
|
24
25
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
25
26
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
26
|
-
actionview (4.2.
|
27
|
-
activesupport (= 4.2.
|
27
|
+
actionview (4.2.7)
|
28
|
+
activesupport (= 4.2.7)
|
28
29
|
builder (~> 3.1)
|
29
30
|
erubis (~> 2.7.0)
|
30
31
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
31
32
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
32
33
|
active_record_union (1.1.1)
|
33
34
|
activerecord (>= 4.0)
|
34
|
-
activejob (4.2.
|
35
|
-
activesupport (= 4.2.
|
35
|
+
activejob (4.2.7)
|
36
|
+
activesupport (= 4.2.7)
|
36
37
|
globalid (>= 0.3.0)
|
37
|
-
activemodel (4.2.
|
38
|
-
activesupport (= 4.2.
|
38
|
+
activemodel (4.2.7)
|
39
|
+
activesupport (= 4.2.7)
|
39
40
|
builder (~> 3.1)
|
40
|
-
activerecord (4.2.
|
41
|
-
activemodel (= 4.2.
|
42
|
-
activesupport (= 4.2.
|
41
|
+
activerecord (4.2.7)
|
42
|
+
activemodel (= 4.2.7)
|
43
|
+
activesupport (= 4.2.7)
|
43
44
|
arel (~> 6.0)
|
44
|
-
activesupport (4.2.
|
45
|
+
activesupport (4.2.7)
|
45
46
|
i18n (~> 0.7)
|
46
47
|
json (~> 1.7, >= 1.7.7)
|
47
48
|
minitest (~> 5.1)
|
48
49
|
thread_safe (~> 0.3, >= 0.3.4)
|
49
50
|
tzinfo (~> 1.1)
|
50
51
|
arel (6.0.3)
|
51
|
-
ast (2.
|
52
|
+
ast (2.3.0)
|
52
53
|
builder (3.2.2)
|
53
54
|
closure_tree (6.0.0)
|
54
55
|
activerecord (>= 4.1.0)
|
@@ -66,7 +67,7 @@ GEM
|
|
66
67
|
factory_girl (~> 4.7.0)
|
67
68
|
railties (>= 3.0.0)
|
68
69
|
ffaker (2.2.0)
|
69
|
-
globalid (0.3.
|
70
|
+
globalid (0.3.7)
|
70
71
|
activesupport (>= 4.1.0)
|
71
72
|
i18n (0.7.0)
|
72
73
|
json (1.8.3)
|
@@ -78,14 +79,16 @@ GEM
|
|
78
79
|
mime-types (3.1)
|
79
80
|
mime-types-data (~> 3.2015)
|
80
81
|
mime-types-data (3.2016.0521)
|
81
|
-
mini_portile2 (2.
|
82
|
+
mini_portile2 (2.1.0)
|
82
83
|
minitest (5.9.0)
|
83
|
-
nokogiri (1.6.
|
84
|
-
mini_portile2 (~> 2.
|
85
|
-
|
84
|
+
nokogiri (1.6.8)
|
85
|
+
mini_portile2 (~> 2.1.0)
|
86
|
+
pkg-config (~> 1.1.7)
|
87
|
+
parser (2.3.1.2)
|
86
88
|
ast (~> 2.2)
|
89
|
+
pkg-config (1.1.7)
|
87
90
|
powerpack (0.1.1)
|
88
|
-
pry (0.10.
|
91
|
+
pry (0.10.4)
|
89
92
|
coderay (~> 1.1.0)
|
90
93
|
method_source (~> 0.8.1)
|
91
94
|
slop (~> 3.4)
|
@@ -94,16 +97,16 @@ GEM
|
|
94
97
|
rack (1.6.4)
|
95
98
|
rack-test (0.6.3)
|
96
99
|
rack (>= 1.0)
|
97
|
-
rails (4.2.
|
98
|
-
actionmailer (= 4.2.
|
99
|
-
actionpack (= 4.2.
|
100
|
-
actionview (= 4.2.
|
101
|
-
activejob (= 4.2.
|
102
|
-
activemodel (= 4.2.
|
103
|
-
activerecord (= 4.2.
|
104
|
-
activesupport (= 4.2.
|
100
|
+
rails (4.2.7)
|
101
|
+
actionmailer (= 4.2.7)
|
102
|
+
actionpack (= 4.2.7)
|
103
|
+
actionview (= 4.2.7)
|
104
|
+
activejob (= 4.2.7)
|
105
|
+
activemodel (= 4.2.7)
|
106
|
+
activerecord (= 4.2.7)
|
107
|
+
activesupport (= 4.2.7)
|
105
108
|
bundler (>= 1.3.0, < 2.0)
|
106
|
-
railties (= 4.2.
|
109
|
+
railties (= 4.2.7)
|
107
110
|
sprockets-rails
|
108
111
|
rails-deprecated_sanitizer (1.0.3)
|
109
112
|
activesupport (>= 4.2.0.alpha)
|
@@ -113,13 +116,13 @@ GEM
|
|
113
116
|
rails-deprecated_sanitizer (>= 1.0.1)
|
114
117
|
rails-html-sanitizer (1.0.3)
|
115
118
|
loofah (~> 2.0)
|
116
|
-
railties (4.2.
|
117
|
-
actionpack (= 4.2.
|
118
|
-
activesupport (= 4.2.
|
119
|
+
railties (4.2.7)
|
120
|
+
actionpack (= 4.2.7)
|
121
|
+
activesupport (= 4.2.7)
|
119
122
|
rake (>= 0.8.7)
|
120
123
|
thor (>= 0.18.1, < 2.0)
|
121
124
|
rainbow (2.1.0)
|
122
|
-
rake (11.
|
125
|
+
rake (11.2.2)
|
123
126
|
rspec (3.4.0)
|
124
127
|
rspec-core (~> 3.4.0)
|
125
128
|
rspec-expectations (~> 3.4.0)
|
@@ -156,19 +159,20 @@ GEM
|
|
156
159
|
simplecov-html (~> 0.10.0)
|
157
160
|
simplecov-html (0.10.0)
|
158
161
|
slop (3.6.0)
|
159
|
-
sprockets (3.
|
162
|
+
sprockets (3.7.0)
|
160
163
|
concurrent-ruby (~> 1.0)
|
161
164
|
rack (> 1, < 3)
|
162
|
-
sprockets-rails (3.
|
165
|
+
sprockets-rails (3.1.1)
|
163
166
|
actionpack (>= 4.0)
|
164
167
|
activesupport (>= 4.0)
|
165
168
|
sprockets (>= 3.0.0)
|
166
169
|
sqlite3 (1.3.11)
|
167
170
|
thor (0.19.1)
|
168
171
|
thread_safe (0.3.5)
|
172
|
+
tqdm (0.3.0)
|
169
173
|
tzinfo (1.2.2)
|
170
174
|
thread_safe (~> 0.1)
|
171
|
-
unicode-display_width (1.0
|
175
|
+
unicode-display_width (1.1.0)
|
172
176
|
with_advisory_lock (3.0.0)
|
173
177
|
activerecord (>= 3.2)
|
174
178
|
thread_safe
|
@@ -183,16 +187,17 @@ DEPENDENCIES
|
|
183
187
|
ffaker (= 2.2.0)
|
184
188
|
monarchy!
|
185
189
|
pry-rails (= 0.3.4)
|
186
|
-
rake (~> 11.1
|
190
|
+
rake (~> 11.1)
|
187
191
|
rspec (= 3.4.0)
|
188
192
|
rspec-rails (= 3.4.2)
|
189
193
|
rubocop (= 0.40.0)
|
190
194
|
shoulda-matchers (= 3.1.1)
|
191
195
|
simplecov (= 0.11.2)
|
192
196
|
sqlite3 (= 1.3.11)
|
197
|
+
tqdm (= 0.3.0)
|
193
198
|
|
194
199
|
RUBY VERSION
|
195
200
|
ruby 2.3.0p0
|
196
201
|
|
197
202
|
BUNDLED WITH
|
198
|
-
1.12.
|
203
|
+
1.12.5
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Monarchy::MembersRole < ActiveRecord::Base
|
3
|
+
self.table_name = 'monarchy_members_roles'
|
4
|
+
|
5
|
+
belongs_to :member, class_name: "::#{Monarchy.member_class}"
|
6
|
+
belongs_to :role, class_name: "::#{Monarchy.role_class}"
|
7
|
+
|
8
|
+
validates :role_id, uniqueness: { scope: :member_id }
|
9
|
+
end
|
@@ -10,12 +10,9 @@ module Monarchy
|
|
10
10
|
|
11
11
|
def setup_monarchy
|
12
12
|
template 'config.rb', 'config/initializers/monarchy.rb'
|
13
|
-
template 'models/user.rb', 'app/models/user.rb'
|
14
|
-
template 'models/hierarchy.rb', 'app/models/monarchy/hierarchy.rb'
|
15
13
|
|
16
14
|
migration_template 'migrations/hierarchy.rb', 'db/migrate/monarchy_create_hierarchies.rb'
|
17
15
|
migration_template 'migrations/membership.rb', 'db/migrate/monarchy_create_memberships.rb'
|
18
|
-
migration_template 'migrations/user.rb', 'db/migrate/monarchy_create_users.rb'
|
19
16
|
end
|
20
17
|
|
21
18
|
def self.next_migration_number(dirname)
|
@@ -2,4 +2,11 @@ Monarchy.configure do |config|
|
|
2
2
|
config.default_role.name = :guest
|
3
3
|
config.default_role.level = 0
|
4
4
|
config.default_role.inherited = false
|
5
|
+
|
6
|
+
config.member_class_name = 'Monarchy::Member'
|
7
|
+
config.role_class_name = 'Monarchy::Role'
|
8
|
+
# config.user_class_name = 'User'
|
9
|
+
|
10
|
+
# config.member_force_revoke = true
|
11
|
+
# config.restricted_role_names = ['member']
|
5
12
|
end
|
@@ -9,18 +9,30 @@ class MonarchyCreateMemberships < ActiveRecord::Migration
|
|
9
9
|
create_table :monarchy_roles do |t|
|
10
10
|
t.string :name, null: false
|
11
11
|
t.integer :level, default: 0, null: false
|
12
|
+
t.integer :inherited_role_id
|
12
13
|
t.boolean :inherited, default: false, null: false
|
13
14
|
t.timestamps null: false
|
14
15
|
end
|
15
16
|
|
16
|
-
add_index :monarchy_roles, :name, unique: true
|
17
|
-
|
18
17
|
create_table :monarchy_members_roles do |t|
|
19
18
|
t.belongs_to :role
|
20
19
|
t.belongs_to :member
|
21
20
|
t.timestamps null: false
|
22
21
|
end
|
23
22
|
|
23
|
+
add_index :monarchy_hierarchies, :parent_id
|
24
|
+
add_index :monarchy_hierarchies, :resource_id
|
25
|
+
|
26
|
+
add_index :monarchy_members, :hierarchy_id
|
27
|
+
add_index :monarchy_members, :user_id
|
28
|
+
|
29
|
+
add_index :monarchy_roles, :level
|
30
|
+
add_index :monarchy_roles, :inherited
|
31
|
+
add_index :monarchy_roles, :inherited_role_id
|
32
|
+
add_index :monarchy_roles, :name, unique: true
|
33
|
+
|
24
34
|
add_index :monarchy_members_roles, [:role_id, :member_id], unique: true
|
35
|
+
add_index :monarchy_members_roles, :member_id
|
36
|
+
add_index :monarchy_members_roles, :role_id
|
25
37
|
end
|
26
38
|
end
|
@@ -8,7 +8,7 @@ module Monarchy
|
|
8
8
|
extend Monarchy::ActsAsHierarchy::SupportMethods
|
9
9
|
has_closure_tree dependent: :destroy
|
10
10
|
|
11
|
-
has_many :members, class_name:
|
11
|
+
has_many :members, class_name: "::#{Monarchy.member_class}", dependent: :destroy
|
12
12
|
belongs_to :resource, polymorphic: true, dependent: :destroy
|
13
13
|
|
14
14
|
include_scopes
|
@@ -40,11 +40,30 @@ module Monarchy
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def accessible_leaves(user)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
descendant_leaves.where('monarchy_hierarchy_hierarchies.descendant_id': descendant_leaves_for_user(user)
|
44
|
+
.where('monarchy_roles.name': restricted_role_names)
|
45
|
+
.select('monarchy_hierarchy_hierarchies.ancestor_id')).union(
|
46
|
+
descendant_leaves
|
47
|
+
.where('monarchy_hierarchy_hierarchies.ancestor_id': descendant_leaves_for_user(user)
|
48
|
+
.where.not('monarchy_roles.name': restricted_role_names))
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def restricted_role_names
|
53
|
+
Array(Monarchy.configuration.restricted_role_names) + [default_role_name]
|
54
|
+
end
|
55
|
+
|
56
|
+
def default_role_name
|
57
|
+
Monarchy.configuration.default_role.name
|
58
|
+
end
|
59
|
+
|
60
|
+
def descendant_leaves_for_user(user)
|
61
|
+
descendant_leaves.joins(members: [:roles]).where(monarchy_members: { user_id: user.id })
|
62
|
+
end
|
63
|
+
|
64
|
+
def descendant_leaves
|
65
|
+
joins('INNER JOIN "monarchy_hierarchy_hierarchies" ON "monarchy_hierarchies"."id" =' \
|
66
|
+
'"monarchy_hierarchy_hierarchies"."descendant_id"')
|
48
67
|
end
|
49
68
|
end
|
50
69
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Monarchy
|
3
|
+
module ActsAsMember
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def acts_as_member
|
8
|
+
extend Monarchy::ActsAsMember::SupportMethods
|
9
|
+
|
10
|
+
self.table_name = 'monarchy_members'
|
11
|
+
|
12
|
+
delegate :resource, :resource_id, :resource_type, to: :hierarchy
|
13
|
+
|
14
|
+
include_relationships
|
15
|
+
include_validators
|
16
|
+
include_callbacks
|
17
|
+
include_scopes
|
18
|
+
|
19
|
+
include Monarchy::ActsAsMember::InstanceMethods
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module SupportMethods
|
24
|
+
def include_scopes
|
25
|
+
scope :accessible_for, (lambda do |user|
|
26
|
+
where(hierarchy: Monarchy::Hierarchy.accessible_for(user))
|
27
|
+
end)
|
28
|
+
end
|
29
|
+
|
30
|
+
def include_callbacks
|
31
|
+
before_create :set_default_role
|
32
|
+
after_destroy :revoke_access, if: :member_force_revoke?
|
33
|
+
end
|
34
|
+
|
35
|
+
def include_validators
|
36
|
+
validates :user_id, uniqueness: { scope: :hierarchy_id }
|
37
|
+
validates :user, presence: true
|
38
|
+
validate :hierarchy_or_resource
|
39
|
+
end
|
40
|
+
|
41
|
+
def include_relationships
|
42
|
+
has_many :members_roles, dependent: :destroy, class_name: 'Monarchy::MembersRole'
|
43
|
+
has_many :roles, -> { order(level: :desc) }, through: :members_roles, class_name: "::#{Monarchy.role_class}"
|
44
|
+
|
45
|
+
belongs_to :user, class_name: "::#{Monarchy.user_class}"
|
46
|
+
belongs_to :hierarchy, class_name: 'Monarchy::Hierarchy'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module InstanceMethods
|
51
|
+
def resource=(resource)
|
52
|
+
self.hierarchy = resource.hierarchy unless hierarchy
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def revoke_access
|
58
|
+
user.revoke_access(resource, resource.hierarchy.descendant_ids)
|
59
|
+
end
|
60
|
+
|
61
|
+
def member_force_revoke?
|
62
|
+
Monarchy.configuration.member_force_revoke
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_default_role
|
66
|
+
roles = self.roles
|
67
|
+
roles << Monarchy.role_class.find_or_create_by(
|
68
|
+
name: Monarchy.configuration.default_role.name,
|
69
|
+
inherited: Monarchy.configuration.default_role.inherited,
|
70
|
+
level: Monarchy.configuration.default_role.level
|
71
|
+
)
|
72
|
+
self.roles = roles.uniq
|
73
|
+
end
|
74
|
+
|
75
|
+
def hierarchy_or_resource
|
76
|
+
errors.add(:base, 'Specify a resource or a hierarchy') unless hierarchy
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
ActiveRecord::Base.send :include, Monarchy::ActsAsMember
|
@@ -6,13 +6,15 @@ module Monarchy
|
|
6
6
|
module ClassMethods
|
7
7
|
def acts_as_resource(options = {})
|
8
8
|
extend Monarchy::ActsAsResource::SupportMethods
|
9
|
+
setup_acting
|
9
10
|
|
10
11
|
parent_as(options[:parent_as]) if options[:parent_as]
|
11
12
|
|
12
13
|
after_create :ensure_hierarchy
|
14
|
+
after_save :assign_parent
|
13
15
|
|
14
|
-
has_many :members, through: :hierarchy, class_name:
|
15
|
-
has_many :users, through: :members, class_name:
|
16
|
+
has_many :members, through: :hierarchy, class_name: "::#{Monarchy.member_class}"
|
17
|
+
has_many :users, through: :members, class_name: "::#{Monarchy.user_class}"
|
16
18
|
has_one :hierarchy, as: :resource, dependent: :destroy, class_name: 'Monarchy::Hierarchy'
|
17
19
|
|
18
20
|
include_scopes
|
@@ -22,24 +24,22 @@ module Monarchy
|
|
22
24
|
end
|
23
25
|
|
24
26
|
module SupportMethods
|
27
|
+
attr_accessor :parentize, :acting_as_resource
|
28
|
+
|
25
29
|
private
|
26
30
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
31
|
+
def setup_acting
|
32
|
+
Monarchy.resource_classes << self
|
33
|
+
@acting_as_resource = true
|
34
|
+
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
self.parent = class_name.find(id)
|
36
|
-
super(id)
|
37
|
-
end
|
36
|
+
def parent_as(name)
|
37
|
+
self.parentize = name
|
38
38
|
end
|
39
39
|
|
40
40
|
def include_scopes
|
41
41
|
scope :in, (lambda do |resource|
|
42
|
-
joins(:hierarchy).where(monarchy_hierarchies: { parent_id: resource.hierarchy.
|
42
|
+
joins(:hierarchy).where(monarchy_hierarchies: { parent_id: resource.hierarchy.self_and_descendants })
|
43
43
|
end)
|
44
44
|
|
45
45
|
scope :accessible_for, (lambda do |user|
|
@@ -80,6 +80,11 @@ module Monarchy
|
|
80
80
|
)
|
81
81
|
end
|
82
82
|
|
83
|
+
def assign_parent(force = false)
|
84
|
+
parent = self.class.parentize
|
85
|
+
self.parent = send(parent) if parent && (send("#{parent}_id_changed?") || force)
|
86
|
+
end
|
87
|
+
|
83
88
|
def children_resources
|
84
89
|
c = hierarchy.try(:children)
|
85
90
|
return nil if c.nil?
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Monarchy
|
3
|
+
module ActsAsRole
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def acts_as_role
|
8
|
+
self.table_name = 'monarchy_roles'
|
9
|
+
|
10
|
+
has_many :members_roles, dependent: :destroy, class_name: 'Monarchy::MembersRole'
|
11
|
+
has_many :members, through: :members_roles, class_name: "::#{Monarchy.member_class}"
|
12
|
+
|
13
|
+
belongs_to :inherited_role, class_name: "::#{Monarchy.role_class}"
|
14
|
+
|
15
|
+
after_create :default_inherited_role
|
16
|
+
|
17
|
+
include Monarchy::ActsAsRole::InstanceMethods
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
private
|
23
|
+
|
24
|
+
def default_inherited_role
|
25
|
+
update(inherited_role_id: id) unless inherited_role
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ActiveRecord::Base.send :include, Monarchy::ActsAsRole
|
@@ -5,17 +5,22 @@ module Monarchy
|
|
5
5
|
|
6
6
|
module ClassMethods
|
7
7
|
def acts_as_user
|
8
|
-
has_many :members, class_name:
|
8
|
+
has_many :members, class_name: "::#{Monarchy.member_class}", dependent: :destroy
|
9
9
|
has_many :hierarchies, through: :members, class_name: 'Monarchy::Hierarchy'
|
10
10
|
|
11
|
+
scope :accessible_for, (lambda do |user|
|
12
|
+
where(id: Monarchy::Hierarchy.accessible_for(user)
|
13
|
+
.joins(members: [:user]).select(:user_id)).union(where(id: user.id))
|
14
|
+
end)
|
15
|
+
|
11
16
|
include Monarchy::ActsAsUser::InstanceMethods
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
15
20
|
module InstanceMethods
|
16
21
|
def roles_for(resource, inheritence = true)
|
17
|
-
return
|
18
|
-
accessible_roles_for(resource, inheritence)
|
22
|
+
return Monarchy.role_class.none unless resource.hierarchy
|
23
|
+
accessible_roles_for(resource, inheritence)
|
19
24
|
end
|
20
25
|
|
21
26
|
def member_for(resource)
|
@@ -28,9 +33,9 @@ module Monarchy
|
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
|
-
def revoke_access(resource)
|
32
|
-
|
33
|
-
members_for(
|
36
|
+
def revoke_access(resource, hierarchy_ids = nil)
|
37
|
+
hierarchy_ids ||= resource.hierarchy.self_and_descendant_ids
|
38
|
+
members_for(hierarchy_ids).delete_all
|
34
39
|
end
|
35
40
|
|
36
41
|
def revoke_role(role_name, resource)
|
@@ -44,30 +49,35 @@ module Monarchy
|
|
44
49
|
private
|
45
50
|
|
46
51
|
def accessible_roles_for(resource, inheritnce)
|
47
|
-
accessible_roles = inheritnce
|
52
|
+
accessible_roles = if inheritnce
|
53
|
+
resource_and_inheritence_roles(resource)
|
54
|
+
else
|
55
|
+
resource_roles(resource).order('level desc')
|
56
|
+
end
|
57
|
+
|
48
58
|
accessible_roles.present? ? accessible_roles : descendant_role(resource)
|
49
59
|
end
|
50
60
|
|
51
61
|
def resource_and_inheritence_roles(resource)
|
52
|
-
hierarchy_ids = resource.hierarchy.
|
53
|
-
Monarchy
|
54
|
-
.where(
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
62
|
+
hierarchy_ids = resource.hierarchy.ancestors.select(:id)
|
63
|
+
Monarchy.role_class.where(id:
|
64
|
+
Monarchy.role_class.joins(:members).where('monarchy_members.user_id': id)
|
65
|
+
.where('monarchy_roles.inherited': 't', 'monarchy_members.hierarchy_id': hierarchy_ids)
|
66
|
+
.select(:inherited_role_id))
|
67
|
+
.union(resource_roles(resource))
|
68
|
+
.distinct
|
59
69
|
end
|
60
70
|
|
61
71
|
def resource_roles(resource)
|
62
|
-
Monarchy
|
63
|
-
|
64
|
-
|
72
|
+
Monarchy.role_class.joins(:members)
|
73
|
+
.where('monarchy_members.hierarchy_id': resource.hierarchy.id, 'monarchy_members.user_id': id)
|
74
|
+
.distinct
|
65
75
|
end
|
66
76
|
|
67
77
|
def descendant_role(resource)
|
68
78
|
descendant_ids = resource.hierarchy.descendant_ids
|
69
79
|
children_access = members_for(descendant_ids).present?
|
70
|
-
children_access ?
|
80
|
+
children_access ? Monarchy.role_class.where(id: default_role) : Monarchy.role_class.none
|
71
81
|
end
|
72
82
|
|
73
83
|
def revoking_role(role_name, resource, force = false)
|
@@ -75,28 +85,29 @@ module Monarchy
|
|
75
85
|
member_roles = member.members_roles
|
76
86
|
|
77
87
|
return revoke_access(resource) if last_role?(member_roles, role_name) && force
|
78
|
-
member_roles.joins(:role).where(monarchy_roles: { name: role_name }).
|
88
|
+
member_roles.joins(:role).where(monarchy_roles: { name: role_name }).delete_all
|
79
89
|
end
|
80
90
|
|
81
91
|
def grant_or_create_member(role_name, resource)
|
82
|
-
role = Monarchy
|
83
|
-
|
92
|
+
role = Monarchy.role_class.find_by(name: role_name)
|
93
|
+
raise 'Role does not exist' unless role
|
84
94
|
|
95
|
+
member = member_for(resource)
|
85
96
|
if member
|
86
97
|
Monarchy::MembersRole.create(member: member, role: role)
|
87
98
|
else
|
88
|
-
member = Monarchy
|
99
|
+
member = Monarchy.member_class.create(user: self, hierarchy: resource.hierarchy, roles: [role])
|
89
100
|
end
|
90
101
|
|
91
102
|
member
|
92
103
|
end
|
93
104
|
|
94
105
|
def members_for(hierarchy_ids)
|
95
|
-
Monarchy
|
106
|
+
Monarchy.member_class.where(hierarchy_id: hierarchy_ids, user_id: id)
|
96
107
|
end
|
97
108
|
|
98
109
|
def default_role
|
99
|
-
@default_role ||= Monarchy
|
110
|
+
@default_role ||= Monarchy.role_class.find_by(name: Monarchy.configuration.default_role.name)
|
100
111
|
end
|
101
112
|
|
102
113
|
def last_role?(member_roles, role_name = nil)
|
data/lib/monarchy/version.rb
CHANGED
data/lib/monarchy.rb
CHANGED
@@ -3,16 +3,43 @@ require 'closure_tree'
|
|
3
3
|
require 'configurations'
|
4
4
|
require 'active_record_union'
|
5
5
|
|
6
|
+
require 'monarchy/acts_as_role'
|
7
|
+
require 'monarchy/acts_as_member'
|
6
8
|
require 'monarchy/acts_as_hierarchy'
|
7
9
|
require 'monarchy/acts_as_resource'
|
8
10
|
require 'monarchy/acts_as_user'
|
9
|
-
require 'monarchy/membership'
|
10
11
|
require 'monarchy/engine'
|
11
12
|
|
12
13
|
module Monarchy
|
14
|
+
cattr_accessor :resource_classes
|
15
|
+
|
16
|
+
def self.resource_classes
|
17
|
+
@resource_classes ||= []
|
18
|
+
end
|
19
|
+
|
13
20
|
include Configurations
|
14
21
|
|
22
|
+
configuration_defaults do |config|
|
23
|
+
config.member_class_name = 'Monarchy::Member'
|
24
|
+
config.role_class_name = 'Monarchy::Role'
|
25
|
+
config.member_force_revoke = false
|
26
|
+
config.restricted_role_names = []
|
27
|
+
end
|
28
|
+
|
15
29
|
not_configured do |prop|
|
16
|
-
raise NoMethodError, "#{prop}
|
30
|
+
raise NoMethodError, "Monarchy requires a #{prop} to be configured"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.member_class
|
34
|
+
Monarchy.configuration.member_class_name.safe_constantize
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.role_class
|
38
|
+
Monarchy.configuration.role_class_name.safe_constantize
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.user_class
|
42
|
+
klass = Monarchy.configuration.user_class_name.safe_constantize
|
43
|
+
klass ? klass : raise(ArgumentError, 'User class has to be initialized or exist!')
|
17
44
|
end
|
18
45
|
end
|
@@ -1,5 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
require 'tqdm'
|
3
|
+
|
4
|
+
task 'monarchy:reparentize' do
|
5
|
+
Monarchy.resource_classes.with_progress.each do |klass|
|
6
|
+
klass.all.each do |model|
|
7
|
+
model.send(:assign_parent, true)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
task 'monarchy:hierarchization' do
|
13
|
+
Monarchy.resource_classes.with_progress.each do |klass|
|
14
|
+
klass.all.each do |model|
|
15
|
+
model.send(:ensure_hierarchy)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/monarchy.gemspec
CHANGED
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_dependency 'closure_tree', '6.0.0'
|
30
30
|
s.add_dependency 'configurations', '2.2.0'
|
31
31
|
s.add_dependency 'active_record_union', '1.1.1'
|
32
|
+
s.add_dependency 'tqdm', '0.3.0'
|
32
33
|
|
33
34
|
s.add_development_dependency 'bundler', '~> 1.10'
|
34
35
|
s.add_development_dependency 'rake', '~> 11.1'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monarchy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Exelord
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05
|
11
|
+
date: 2016-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -72,6 +72,20 @@ dependencies:
|
|
72
72
|
- - '='
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 1.1.1
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: tqdm
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 0.3.0
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 0.3.0
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
90
|
name: bundler
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,6 +147,9 @@ files:
|
|
133
147
|
- README.md
|
134
148
|
- Rakefile
|
135
149
|
- app/models/monarchy/hierarchy.rb
|
150
|
+
- app/models/monarchy/member.rb
|
151
|
+
- app/models/monarchy/members_role.rb
|
152
|
+
- app/models/monarchy/role.rb
|
136
153
|
- bin/console
|
137
154
|
- bin/setup
|
138
155
|
- lib/generators/monarchy/resource_generator.rb
|
@@ -141,16 +158,14 @@ files:
|
|
141
158
|
- lib/generators/templates/migrations/hierarchy.rb
|
142
159
|
- lib/generators/templates/migrations/membership.rb
|
143
160
|
- lib/generators/templates/migrations/resource.rb
|
144
|
-
- lib/generators/templates/migrations/user.rb
|
145
|
-
- lib/generators/templates/models/hierarchy.rb
|
146
161
|
- lib/generators/templates/models/resource.rb
|
147
|
-
- lib/generators/templates/models/user.rb
|
148
162
|
- lib/monarchy.rb
|
149
163
|
- lib/monarchy/acts_as_hierarchy.rb
|
164
|
+
- lib/monarchy/acts_as_member.rb
|
150
165
|
- lib/monarchy/acts_as_resource.rb
|
166
|
+
- lib/monarchy/acts_as_role.rb
|
151
167
|
- lib/monarchy/acts_as_user.rb
|
152
168
|
- lib/monarchy/engine.rb
|
153
|
-
- lib/monarchy/membership.rb
|
154
169
|
- lib/monarchy/version.rb
|
155
170
|
- lib/tasks/monarchy_tasks.rake
|
156
171
|
- monarchy.gemspec
|
data/lib/monarchy/membership.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module Monarchy
|
3
|
-
class Member < ActiveRecord::Base
|
4
|
-
self.table_name = 'monarchy_members'
|
5
|
-
|
6
|
-
has_many :members_roles, dependent: :destroy, class_name: 'Monarchy::MembersRole'
|
7
|
-
has_many :roles, through: :members_roles, class_name: 'Monarchy::Role'
|
8
|
-
|
9
|
-
belongs_to :user
|
10
|
-
belongs_to :hierarchy, class_name: 'Monarchy::Hierarchy'
|
11
|
-
|
12
|
-
delegate :resource, :resource=, :resource_id, :resource_type, to: :hierarchy
|
13
|
-
|
14
|
-
validates :user_id, uniqueness: { scope: :hierarchy_id }
|
15
|
-
validates :user, presence: true
|
16
|
-
|
17
|
-
validate :hierarchy_or_resource
|
18
|
-
|
19
|
-
before_create :set_default_role
|
20
|
-
|
21
|
-
scope :accessible_for, (lambda do |user|
|
22
|
-
where(hierarchy: Monarchy::Hierarchy.accessible_for(user))
|
23
|
-
end)
|
24
|
-
|
25
|
-
def resource=(resource)
|
26
|
-
self.hierarchy = resource.hierarchy unless hierarchy
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def set_default_role
|
32
|
-
roles = self.roles
|
33
|
-
roles << Monarchy::Role.find_or_create_by(
|
34
|
-
name: Monarchy.configuration.default_role.name,
|
35
|
-
inherited: Monarchy.configuration.default_role.inherited,
|
36
|
-
level: Monarchy.configuration.default_role.level
|
37
|
-
)
|
38
|
-
self.roles = roles.uniq
|
39
|
-
end
|
40
|
-
|
41
|
-
def hierarchy_or_resource
|
42
|
-
errors.add(:base, 'Specify a resource or a hierarchy') unless hierarchy
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class Role < ActiveRecord::Base
|
47
|
-
self.table_name = 'monarchy_roles'
|
48
|
-
|
49
|
-
has_many :members_roles, dependent: :destroy, class_name: 'Monarchy::MembersRole'
|
50
|
-
has_many :members, through: :members_roles, class_name: 'Monarchy::Member'
|
51
|
-
end
|
52
|
-
|
53
|
-
class MembersRole < ActiveRecord::Base
|
54
|
-
self.table_name = 'monarchy_members_roles'
|
55
|
-
|
56
|
-
belongs_to :member, class_name: 'Monarchy::Member'
|
57
|
-
belongs_to :role, class_name: 'Monarchy::Role'
|
58
|
-
|
59
|
-
validates :role_id, uniqueness: { scope: :member_id }
|
60
|
-
end
|
61
|
-
end
|