card-mod-permissions 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/set/abstract/permission.rb +122 -0
- data/set/all/permissions.rb +227 -0
- data/set/all/update_read_rules.rb +12 -0
- data/set/right/create.rb +1 -0
- data/set/right/delete.rb +1 -0
- data/set/right/read.rb +79 -0
- data/set/right/update.rb +1 -0
- data/set/self/create.rb +3 -0
- data/set/self/delete.rb +3 -0
- data/set/self/read.rb +3 -0
- data/set/self/update.rb +3 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 979a6aa27a0485313d0b7c8716ce592eb4a006d8de7b0d72b93818fcaba9e168
|
4
|
+
data.tar.gz: 4ec1cebed12cc29ae51379cdeb255c43483533f39f3bfc5737f97e603757a55c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2561983f02c9b533f50f8e9c3a13f510b83d159d16d75dd5f20173cad22db7451e183cde9ec69f5e83a799c4017e017c8a1c473ff662fbe1ee2e51893e5e4e51
|
7
|
+
data.tar.gz: e536cbe5b71e9f486c224e918b46889a9b23666d7536ad67cdf87237a93830923e193319bac81739e463b9706f0a7a5e403d3f2760b33df9fb54845078175da5
|
@@ -0,0 +1,122 @@
|
|
1
|
+
|
2
|
+
def standardize_items
|
3
|
+
super unless content == "_left"
|
4
|
+
end
|
5
|
+
|
6
|
+
def options_rule_card
|
7
|
+
Card[:cards_with_account]
|
8
|
+
end
|
9
|
+
|
10
|
+
format :html do
|
11
|
+
view :pointer_core do
|
12
|
+
wrap_with :div, pointer_items, class: "pointer-list"
|
13
|
+
end
|
14
|
+
|
15
|
+
view :core, cache: :never do
|
16
|
+
if card.content == "_left"
|
17
|
+
core_inherit_content
|
18
|
+
else
|
19
|
+
render! :pointer_core
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
view :one_line_content, cache: :never do
|
24
|
+
render_core items: { view: :link }
|
25
|
+
end
|
26
|
+
|
27
|
+
view :input do
|
28
|
+
item_names = inheriting? ? [] : card.item_names
|
29
|
+
%(
|
30
|
+
#{_render_hidden_content_field}
|
31
|
+
<div class="perm-editor">
|
32
|
+
#{inheritance_checkbox}
|
33
|
+
<div class="perm-group perm-vals perm-section">
|
34
|
+
<h5 class="text-muted">Groups</h5>
|
35
|
+
#{groups item_names}
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<div class="perm-indiv perm-vals perm-section">
|
39
|
+
<h5 class="text-muted">Individuals</h5>
|
40
|
+
#{list_input item_list: item_names, extra_css_class: 'perm-indiv-ul'}
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def groups item_names
|
49
|
+
group_options.map do |option|
|
50
|
+
checked = !item_names.delete(option.name).nil?
|
51
|
+
icon = icon_tag "open_in_new", "link-muted"
|
52
|
+
option_link = link_to_card option.name, icon, target: "decko_role"
|
53
|
+
box = check_box_tag "#{option.key}-perm-checkbox",
|
54
|
+
option.name, checked, class: "perm-checkbox-button"
|
55
|
+
<<-HTML
|
56
|
+
<div class="form-check checkbox">
|
57
|
+
<label class="form-check-label">
|
58
|
+
#{box} #{option.name} #{option_link}
|
59
|
+
</label>
|
60
|
+
</div>
|
61
|
+
HTML
|
62
|
+
end * "\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
def group_options
|
66
|
+
Auth.as_bot do
|
67
|
+
Card.search({ type_id: RoleID, sort: "name" }, "roles by name")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def inheritable?
|
72
|
+
@inheritable ||=
|
73
|
+
begin
|
74
|
+
set_name = card.name.trunk_name
|
75
|
+
set_card = Card.fetch(set_name)
|
76
|
+
not_set = set_card && set_card.type_id != SetID
|
77
|
+
not_set ? false : set_card.inheritable?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def inheriting?
|
82
|
+
@inheriting ||= inheritable? && card.content == "_left"
|
83
|
+
end
|
84
|
+
|
85
|
+
def inheritance_checkbox
|
86
|
+
return unless inheritable?
|
87
|
+
<<-HTML
|
88
|
+
<div class="perm-inheritance perm-section">
|
89
|
+
#{check_box_tag 'inherit', 'inherit', inheriting?}
|
90
|
+
<label>
|
91
|
+
#{core_inherit_content}
|
92
|
+
#{wrap_with(:a, title: "use left's #{card.name.tag} rule") { '?' }}
|
93
|
+
</label>
|
94
|
+
</div>
|
95
|
+
HTML
|
96
|
+
end
|
97
|
+
|
98
|
+
def core_inherit_content
|
99
|
+
text = if in_context_of_self_set?
|
100
|
+
core_inherit_for_content_for_self_set
|
101
|
+
else
|
102
|
+
"Inherit from left card"
|
103
|
+
end
|
104
|
+
%(<span class="inherit-perm">#{text}</span>)
|
105
|
+
end
|
106
|
+
|
107
|
+
def in_context_of_self_set?
|
108
|
+
return false unless @set_context
|
109
|
+
@set_context.to_name.tag_name.key == Card[:self].key
|
110
|
+
end
|
111
|
+
|
112
|
+
def core_inherit_for_content_for_self_set
|
113
|
+
task = card.tag.codename
|
114
|
+
ancestor = Card[@set_context.trunk_name.trunk_name]
|
115
|
+
links = ancestor.who_can(task).map do |card_id|
|
116
|
+
link_to_card card_id, nil, target: args[:target]
|
117
|
+
end * ", "
|
118
|
+
"Inherit ( #{links} )"
|
119
|
+
rescue
|
120
|
+
"Inherit"
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
module ClassMethods
|
2
|
+
def repair_all_permissions
|
3
|
+
Card.where("(read_rule_class is null or read_rule_id is null) and trash is false")
|
4
|
+
.each do |broken_card|
|
5
|
+
broken_card.include_set_modules
|
6
|
+
broken_card.repair_permissions!
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def repair_permissions!
|
12
|
+
rule_id, rule_class = permission_rule_id_and_class :read
|
13
|
+
update_columns read_rule_id: rule_id, read_rule_class: rule_class
|
14
|
+
end
|
15
|
+
|
16
|
+
# ok? and ok! are public facing methods to approve one action at a time
|
17
|
+
#
|
18
|
+
# fetching: if the optional :trait parameter is supplied, it is passed
|
19
|
+
# to fetch and the test is perfomed on the fetched card, therefore:
|
20
|
+
#
|
21
|
+
# trait: :account would fetch this card plus a tag codenamed :account
|
22
|
+
# trait: :roles, new: {} would initialize a new card with default ({})
|
23
|
+
# options.
|
24
|
+
|
25
|
+
def ok? action
|
26
|
+
@ok ||= {}
|
27
|
+
aok = @ok[Auth.as_id] ||= {}
|
28
|
+
if (cached = aok[action])
|
29
|
+
cached
|
30
|
+
else
|
31
|
+
aok[action] = send "ok_to_#{action}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def ok! action
|
36
|
+
raise Card::Error::PermissionDenied, self unless ok? action
|
37
|
+
end
|
38
|
+
|
39
|
+
def who_can action
|
40
|
+
permission_rule_card(action).item_cards.map(&:id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def anyone_can? action
|
44
|
+
who_can(action).include? AnyoneID
|
45
|
+
end
|
46
|
+
|
47
|
+
def direct_rule_card action
|
48
|
+
direct_rule_id = rule_card_id action
|
49
|
+
require_permission_rule! direct_rule_id, action
|
50
|
+
Card.quick_fetch direct_rule_id
|
51
|
+
end
|
52
|
+
|
53
|
+
def permission_rule_id action
|
54
|
+
if junction? && rule(action).match?(/^\[?\[?_left\]?\]?$/)
|
55
|
+
left_permission_rule_id action
|
56
|
+
else
|
57
|
+
rule_card_id(action)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def permission_rule_id_and_class action
|
62
|
+
[permission_rule_id(action), direct_rule_card(action).rule_class_name]
|
63
|
+
end
|
64
|
+
|
65
|
+
def left_permission_rule_id action
|
66
|
+
lcard = left_or_new(skip_virtual: true, skip_modules: true)
|
67
|
+
if action == :create && lcard.real? && lcard.action != :create
|
68
|
+
action = :update
|
69
|
+
end
|
70
|
+
lcard.permission_rule_id action
|
71
|
+
end
|
72
|
+
|
73
|
+
def permission_rule_card action
|
74
|
+
Card.fetch permission_rule_id(action)
|
75
|
+
end
|
76
|
+
|
77
|
+
def require_permission_rule! rule_id, action
|
78
|
+
return if rule_id
|
79
|
+
# RULE missing. should not be possible.
|
80
|
+
# generalize this to handling of all required rules
|
81
|
+
errors.add :permission_denied, tr(:error_no_action_rule, action: action, name: name)
|
82
|
+
raise Card::Error::PermissionDenied, self
|
83
|
+
end
|
84
|
+
|
85
|
+
def rule_class_name
|
86
|
+
trunk.type_id == SetID ? name.trunk_name.tag : nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def you_cant what
|
90
|
+
"You don't have permission to #{what}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def deny_because why
|
94
|
+
@permission_errors << why if @permission_errors
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
def permitted? action
|
99
|
+
return false if Card.config.read_only # :read does not call #permit
|
100
|
+
return true if Auth.always_ok?
|
101
|
+
|
102
|
+
Auth.as_card.among? who_can(action)
|
103
|
+
end
|
104
|
+
|
105
|
+
def permit action, verb=nil
|
106
|
+
# not called by ok_to_read
|
107
|
+
if Card.config.read_only
|
108
|
+
deny_because "Currently in read-only mode"
|
109
|
+
return false
|
110
|
+
end
|
111
|
+
|
112
|
+
return true if permitted? action
|
113
|
+
verb ||= action.to_s
|
114
|
+
deny_because you_cant("#{verb} #{name.present? ? name : 'this'}")
|
115
|
+
end
|
116
|
+
|
117
|
+
def ok_to_create
|
118
|
+
return false unless permit :create
|
119
|
+
return true if simple?
|
120
|
+
|
121
|
+
%i[left right].find { |side| !ok_to_create_side side } ? false : true
|
122
|
+
end
|
123
|
+
|
124
|
+
def ok_to_create_side side
|
125
|
+
# left is supercard; create permissions will get checked there.
|
126
|
+
return true if side == :left && superleft
|
127
|
+
part_card = send side, new: {}
|
128
|
+
# if no card, there must be other errors
|
129
|
+
return true unless part_card&.new_card? && !part_card.ok?(:create)
|
130
|
+
|
131
|
+
deny_because you_cant("create #{part_card.name}")
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
def ok_to_read
|
136
|
+
return true if Auth.always_ok?
|
137
|
+
|
138
|
+
self.read_rule_id ||= permission_rule_id :read
|
139
|
+
return true if Auth.as_card.read_rules_hash[read_rule_id]
|
140
|
+
|
141
|
+
deny_because you_cant "read this"
|
142
|
+
end
|
143
|
+
|
144
|
+
def ok_to_update
|
145
|
+
return false unless permit(:update)
|
146
|
+
return true unless type_id_changed? && !permitted?(:create)
|
147
|
+
deny_because you_cant("change to this type (need create permission)")
|
148
|
+
end
|
149
|
+
|
150
|
+
def ok_to_delete
|
151
|
+
permit :delete
|
152
|
+
end
|
153
|
+
|
154
|
+
# don't know why we introduced this
|
155
|
+
# but we have to preserve read rules to make
|
156
|
+
# delete acts visible in recent changes -pk
|
157
|
+
# event :clear_read_rule, :store, on: :delete do
|
158
|
+
# self.read_rule_id = self.read_rule_class = nil
|
159
|
+
# end
|
160
|
+
|
161
|
+
event :set_read_rule, :store, on: :save, changed: %i[type_id name] do
|
162
|
+
read_rule_id, read_rule_class = permission_rule_id_and_class(:read)
|
163
|
+
self.read_rule_id = read_rule_id
|
164
|
+
self.read_rule_class = read_rule_class
|
165
|
+
end
|
166
|
+
|
167
|
+
event :set_field_read_rules, after: :set_read_rule, on: :update, changed: :type_id do
|
168
|
+
each_field_as_bot(&:update_read_rule)
|
169
|
+
end
|
170
|
+
|
171
|
+
def update_field_read_rules
|
172
|
+
return unless type_id_changed? || read_rule_id_changed?
|
173
|
+
each_field_as_bot do |field|
|
174
|
+
field.update_read_rule if field.rule(:read) == "_left"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def each_field_as_bot
|
179
|
+
# find all cards with me as trunk and update their read_rule
|
180
|
+
# (because of *type plus right)
|
181
|
+
# skip if name is updated because will already be resaved
|
182
|
+
Auth.as_bot do
|
183
|
+
fields.each { |field| yield field }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def without_timestamps
|
188
|
+
Card.record_timestamps = false
|
189
|
+
yield
|
190
|
+
ensure
|
191
|
+
Card.record_timestamps = true
|
192
|
+
end
|
193
|
+
|
194
|
+
event :update_read_rule do
|
195
|
+
without_timestamps do
|
196
|
+
reset_patterns # why is this needed?
|
197
|
+
rcard_id, rclass = permission_rule_id_and_class :read
|
198
|
+
# these two are just to make sure vals are correct on current object
|
199
|
+
self.read_rule_id = rcard_id
|
200
|
+
self.read_rule_class = rclass
|
201
|
+
Card.where(id: id).update_all read_rule_id: rcard_id, read_rule_class: rclass
|
202
|
+
expire :hard
|
203
|
+
update_field_read_rules
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def add_to_read_rule_update_queue updates
|
208
|
+
@read_rule_update_queue = Array.wrap(@read_rule_update_queue).concat updates
|
209
|
+
end
|
210
|
+
|
211
|
+
event :check_permissions, :validate do
|
212
|
+
track_permission_errors do
|
213
|
+
ok? action_for_permission_check
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def action_for_permission_check
|
218
|
+
commenting? ? :update : action
|
219
|
+
end
|
220
|
+
|
221
|
+
def track_permission_errors
|
222
|
+
@permission_errors = []
|
223
|
+
result = yield
|
224
|
+
@permission_errors.each { |msg| errors.add :permission_denied, msg }
|
225
|
+
@permission_errors = nil
|
226
|
+
result
|
227
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
# FIXME: the following don't really belong here, but they have to come after
|
3
|
+
# the reference stuff. we need to organize a bit!
|
4
|
+
|
5
|
+
event :update_rule_cache, :finalize, when: :is_rule? do
|
6
|
+
Card::Rule.clear_rule_cache
|
7
|
+
end
|
8
|
+
|
9
|
+
event :expire_related, :finalize do
|
10
|
+
reset_patterns
|
11
|
+
structuree_names.each { |name| Director.expirees << name } if is_structure?
|
12
|
+
end
|
data/set/right/create.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
include_set Abstract::Permission
|
data/set/right/delete.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
include_set Abstract::Permission
|
data/set/right/read.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
include Abstract::Permission
|
2
|
+
|
3
|
+
format :html do include Abstract::Permission::HtmlFormat end
|
4
|
+
|
5
|
+
event :cascade_read_rule, :finalize, after: :update_rule_cache, when: :is_rule? do
|
6
|
+
return unless name_is_changing? || trash_is_changing?
|
7
|
+
|
8
|
+
update_read_ruled_cards
|
9
|
+
end
|
10
|
+
|
11
|
+
def update_read_ruled_cards
|
12
|
+
Card::Rule.clear_read_rule_cache
|
13
|
+
Card.cache.reset # maybe be more surgical, just Auth.user related
|
14
|
+
expire # probably shouldn't be necessary,
|
15
|
+
# but was sometimes getting cached version when card should be in the
|
16
|
+
# trash. could be related to other bugs?
|
17
|
+
|
18
|
+
processed = update_read_rules_of_set_members
|
19
|
+
update_cards_with_read_rule_id processed unless new?
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_read_rules_of_set_members
|
23
|
+
return unless rule_pattern_index
|
24
|
+
|
25
|
+
each_member do |member, processed|
|
26
|
+
processed << member.key
|
27
|
+
member.update_read_rule unless member_has_overriding_rule?(member)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def member_has_overriding_rule? member
|
32
|
+
pattern_index(Card.fetch_id(member.read_rule_class)) < rule_pattern_index
|
33
|
+
end
|
34
|
+
|
35
|
+
# cards with this card as a read_rule_id
|
36
|
+
# These may include cards that are no longer set members if the card was renamed
|
37
|
+
# (edge case)
|
38
|
+
def update_cards_with_read_rule_id processed
|
39
|
+
processed ||= ::Set.new
|
40
|
+
Card::Auth.as_bot do
|
41
|
+
Card.search(read_rule_id: id) do |card|
|
42
|
+
card.update_read_rule unless processed.include?(card.key)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def each_member
|
48
|
+
Auth.as_bot do
|
49
|
+
all_members.each_with_object(::Set.new) do |member, processed|
|
50
|
+
yield member, processed
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def all_members
|
56
|
+
rule_set.item_cards limit: 0
|
57
|
+
end
|
58
|
+
|
59
|
+
def rule_pattern_index
|
60
|
+
return if trash
|
61
|
+
|
62
|
+
@rule_pattern_index ||= pattern_index rule_set&.tag&.id
|
63
|
+
end
|
64
|
+
|
65
|
+
def pattern_index pattern_id
|
66
|
+
pattern_ids.index(pattern_id) || invalid_pattern_id(pattern_id)
|
67
|
+
end
|
68
|
+
|
69
|
+
def pattern_ids
|
70
|
+
@pattern_ids ||= set_patterns.map(&:pattern_id)
|
71
|
+
end
|
72
|
+
|
73
|
+
def invalid_pattern_id pattern_id
|
74
|
+
Rails.logger.info "invalid pattern id for read rule: #{pattern_id}"
|
75
|
+
end
|
76
|
+
|
77
|
+
event :process_read_rule_update_queue, :finalize do
|
78
|
+
left&.update_read_rule
|
79
|
+
end
|
data/set/right/update.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
include_set Abstract::Permission
|
data/set/self/create.rb
ADDED
data/set/self/delete.rb
ADDED
data/set/self/read.rb
ADDED
data/set/self/update.rb
ADDED
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: card-mod-permissions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.11.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ethan McCutchen
|
8
|
+
- Philipp Kühl
|
9
|
+
- Gerry Gleason
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2020-12-24 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: card
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.101.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - '='
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 1.101.0
|
29
|
+
description: ''
|
30
|
+
email:
|
31
|
+
- info@decko.org
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- set/abstract/permission.rb
|
37
|
+
- set/all/permissions.rb
|
38
|
+
- set/all/update_read_rules.rb
|
39
|
+
- set/right/create.rb
|
40
|
+
- set/right/delete.rb
|
41
|
+
- set/right/read.rb
|
42
|
+
- set/right/update.rb
|
43
|
+
- set/self/create.rb
|
44
|
+
- set/self/delete.rb
|
45
|
+
- set/self/read.rb
|
46
|
+
- set/self/update.rb
|
47
|
+
homepage: http://decko.org
|
48
|
+
licenses:
|
49
|
+
- GPL-3.0
|
50
|
+
metadata:
|
51
|
+
card-mod: permissions
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.5'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubygems_version: 3.0.3
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: decko permissions
|
71
|
+
test_files: []
|