card-mod-permissions 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1 @@
1
+ include_set Abstract::Permission
@@ -0,0 +1 @@
1
+ include_set Abstract::Permission
@@ -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
@@ -0,0 +1 @@
1
+ include_set Abstract::Permission
@@ -0,0 +1,3 @@
1
+ setting_opts group: :permission, position: 1, rule_type_editable: false,
2
+ short_help_text: "who can create cards",
3
+ help_text: "Who can create new cards"
@@ -0,0 +1,3 @@
1
+ setting_opts group: :permission, position: 4, rule_type_editable: false,
2
+ short_help_text: "who can delete cards",
3
+ help_text: "Who can delete cards"
@@ -0,0 +1,3 @@
1
+ setting_opts group: :permission, position: 2, rule_type_editable: false,
2
+ short_help_text: "who can view cards",
3
+ help_text: "Who can view cards in the [[set]]."
@@ -0,0 +1,3 @@
1
+ setting_opts group: :permission, position: 3, rule_type_editable: false,
2
+ short_help_text: "who can update cards",
3
+ help_text: "Who can update cards"
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: []