card-mod-permissions 0.11.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.
@@ -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: []