mikras_utils 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mikras_utils/mkacl/generators/acl_functions.rb +2 -2
- data/lib/mikras_utils/mkacl/generators/id_functions.rb +30 -23
- data/lib/mikras_utils/mkacl/generators/role_functions.rb +96 -27
- data/lib/mikras_utils/mkacl/generators/rules.rb +1 -1
- data/lib/mikras_utils/mkacl/parser.rb +1 -1
- data/lib/mikras_utils/mkacl.rb +8 -1
- data/lib/mikras_utils/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c7d48444e75236d0188b539182a80aefeaea2770cdf7982188d7f055c8b552e
|
4
|
+
data.tar.gz: 5d790361a1c314d7bda6013c1db9c904b50c81f3be39c8396d6c9e4da43e68bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e117ef1b45f0217ec14065d37405cf4b043259465c82a7df09caebc416a60ec15b80293c45c349ffb9cd0b9bd07fe8b9420b85e19f24a88a5dd62d3be62380f
|
7
|
+
data.tar.gz: 285faf4c815810af7111d49176218401f86afc1568a915c721ee67787cbb11df2cd6c016bad9d7b33db61b6120d5726d65aa8e2f0d27fc4cfb06a5685f69de9f
|
@@ -68,8 +68,8 @@ module MkAcl
|
|
68
68
|
_domain_id integer;
|
69
69
|
_acls integer[]; -- per-rule ACLs
|
70
70
|
_acl_select integer[][]; -- per-action ACLs
|
71
|
-
_acl_update integer[][];
|
72
|
-
_acl_delete integer[][];
|
71
|
+
_acl_update integer[][]; --
|
72
|
+
_acl_delete integer[][]; --
|
73
73
|
begin
|
74
74
|
).align
|
75
75
|
indent {
|
@@ -9,7 +9,7 @@ module MkAcl
|
|
9
9
|
|
10
10
|
# Map from domain table to list of [table, path, links] tuples. The
|
11
11
|
# entries describes the SQL link chain from the table to the given domain
|
12
|
-
# table (cases or
|
12
|
+
# table (cases, events, or visits)
|
13
13
|
attr_reader :chains
|
14
14
|
|
15
15
|
def initialize(generator)
|
@@ -30,7 +30,7 @@ module MkAcl
|
|
30
30
|
meta.chains
|
31
31
|
where src_schema_name = '#{app_schema}'
|
32
32
|
and dst_schema_name = '#{app_schema}'
|
33
|
-
and dst_table_name in (
|
33
|
+
and dst_table_name in #{conn.quote_value_list(DOMAIN_TABLES)}
|
34
34
|
)
|
35
35
|
|
36
36
|
generate_per_table_id_functions
|
@@ -45,10 +45,10 @@ module MkAcl
|
|
45
45
|
# def table_seq() @table_seq ||= spec.tables.map(&:uid).join(', ') end
|
46
46
|
|
47
47
|
# Generate a set of per-table functions that returns the associated
|
48
|
-
# case_id/event_id for the given record. The Functions are
|
49
|
-
# each table in the spec file
|
48
|
+
# case_id/event_id/vist_id for the given record. The Functions are
|
49
|
+
# generated for each table in the spec file
|
50
50
|
#
|
51
|
-
# The geneated functions are
|
51
|
+
# The geneated functions are
|
52
52
|
#
|
53
53
|
# case_id_of_RECORD(id integer)
|
54
54
|
# event_id_of_RECORD(id integer)
|
@@ -72,7 +72,7 @@ module MkAcl
|
|
72
72
|
#
|
73
73
|
def generate_per_table_id_functions
|
74
74
|
# Generate functions by domain
|
75
|
-
for domain in
|
75
|
+
for domain in DOMAINS
|
76
76
|
|
77
77
|
# Create the identity functions first. The identity functions are
|
78
78
|
# case_id_of_case() and event_id_of_event(). This makes some stuff
|
@@ -95,7 +95,7 @@ module MkAcl
|
|
95
95
|
record_name = Prick::Inflector.singularize(table_name)
|
96
96
|
id_arg = "_#{id_field}"
|
97
97
|
signature = "#{acl_schema}.#{id_field}_of_#{record_name}(#{id_arg} integer)"
|
98
|
-
puts "drop function if exists #{signature} cascade;"
|
98
|
+
puts "drop function if exists #{signature} cascade;"
|
99
99
|
puts "create function #{signature} returns integer as $$"
|
100
100
|
indent {
|
101
101
|
tables.pop
|
@@ -120,14 +120,17 @@ module MkAcl
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
+
# Tables that references visits, events, and cases
|
124
|
+
visit_tables = chains['visits'].map(&:first)
|
125
|
+
|
123
126
|
# Tables that references events and cases
|
124
|
-
event_tables = chains['events'].map(&:first)
|
127
|
+
event_tables = chains['events'].map(&:first) - visit_tables
|
125
128
|
|
126
|
-
# Tables that references only cases
|
129
|
+
# Tables that references only cases
|
127
130
|
case_tables = chains['cases'].map(&:first) - event_tables
|
128
131
|
|
129
132
|
# Create domain functions
|
130
|
-
for domain, tables in { case: case_tables, event: event_tables }
|
133
|
+
for domain, tables in { case: case_tables, event: event_tables, visit: visit_tables }
|
131
134
|
for table_name in tables
|
132
135
|
record_name = Prick::Inflector.singularize(table_name)
|
133
136
|
signature = "#{acl_schema}.domain_id_of_#{record_name}(_id integer)"
|
@@ -154,7 +157,7 @@ module MkAcl
|
|
154
157
|
# specialized versions above
|
155
158
|
#
|
156
159
|
def generate_general_id_functions
|
157
|
-
for domain in
|
160
|
+
for domain in DOMAINS
|
158
161
|
domain_table = Prick::Inflector.pluralize(domain)
|
159
162
|
field = "#{domain}_id"
|
160
163
|
signature = "#{acl_schema}.#{field}_of(_table varchar, _id integer)"
|
@@ -162,7 +165,7 @@ module MkAcl
|
|
162
165
|
puts %(
|
163
166
|
drop function if exists #{signature} cascade;
|
164
167
|
create function #{signature} returns integer as $$
|
165
|
-
select
|
168
|
+
select
|
166
169
|
).align
|
167
170
|
indent(2) {
|
168
171
|
puts "case _table"
|
@@ -174,6 +177,7 @@ module MkAcl
|
|
174
177
|
end
|
175
178
|
puts "when 'cases' then _id"
|
176
179
|
puts "when 'events' then _id"
|
180
|
+
puts "when 'visits' then _id"
|
177
181
|
puts "else null"
|
178
182
|
}
|
179
183
|
puts "end case;"
|
@@ -187,7 +191,11 @@ module MkAcl
|
|
187
191
|
-- FIXME: Ugly implementation
|
188
192
|
drop function if exists #{signature} cascade;
|
189
193
|
create function #{signature} returns integer as $$
|
190
|
-
select coalesce(
|
194
|
+
select coalesce(
|
195
|
+
acl_portal.visit_id_of(_table, _id),
|
196
|
+
acl_portal.event_id_of(_table, _id),
|
197
|
+
acl_portal.case_id_of(_table, _id)
|
198
|
+
);
|
191
199
|
$$ language sql;
|
192
200
|
).align
|
193
201
|
puts
|
@@ -199,8 +207,8 @@ module MkAcl
|
|
199
207
|
# event_id_of(r record)
|
200
208
|
# domain_id_of(r record)
|
201
209
|
#
|
202
|
-
# Returns the case or
|
203
|
-
# record should be an ACL table record type
|
210
|
+
# Returns the case, event, or visit id associated with the given record.
|
211
|
+
# The record should be an ACL table record type
|
204
212
|
#
|
205
213
|
# Very useful in before insert triggers because it takes a record (eg.
|
206
214
|
# NEW) instead of an ID
|
@@ -216,7 +224,7 @@ module MkAcl
|
|
216
224
|
where schema_name = '#{app_schema}'
|
217
225
|
)).group_by(&:table_name)
|
218
226
|
|
219
|
-
for domain in
|
227
|
+
for domain in MkAcl::DOMAINS
|
220
228
|
domain_id_field = "#{domain}_id"
|
221
229
|
signature = "#{acl_schema}.#{domain_id_field}_of(_r record)"
|
222
230
|
puts %(
|
@@ -233,22 +241,22 @@ module MkAcl
|
|
233
241
|
).align
|
234
242
|
indent {
|
235
243
|
indent {
|
236
|
-
|
237
|
-
|
238
244
|
for table in spec.tables
|
239
245
|
next if domain == "event" && table.domain == "case"
|
240
|
-
|
241
|
-
# p table.name
|
242
|
-
# p links.keys
|
246
|
+
next if domain == "visit" && table.domain == "event"
|
243
247
|
link = links[table.name]&.first or next
|
244
248
|
if table.name == "cases"
|
245
249
|
puts "when '#{table.uid}' then return _r.id;"
|
246
250
|
elsif domain == "event" && table.name == "events"
|
247
251
|
puts "when '#{table.uid}' then return _r.id;"
|
252
|
+
elsif domain == "visit" && table.name == "visits"
|
253
|
+
puts "when '#{table.uid}' then return _r.id;"
|
248
254
|
elsif link.ref_table_name == "cases"
|
249
255
|
puts "when '#{table.uid}' then return _r.#{link.column_name};"
|
250
256
|
elsif link.ref_table_name == "events" && table.domain == "event"
|
251
257
|
puts "when '#{table.uid}' then return _r.#{link.column_name};"
|
258
|
+
elsif link.ref_table_name == "visits" && table.domain == "visit"
|
259
|
+
puts "when '#{table.uid}' then return _r.#{link.column_name};"
|
252
260
|
else
|
253
261
|
ref_record = spec[link.ref_table_name]&.record_name or next
|
254
262
|
id_of_function = "#{acl_schema}.#{domain_id_field}_of_#{ref_record}"
|
@@ -276,9 +284,8 @@ module MkAcl
|
|
276
284
|
declare
|
277
285
|
_id integer;
|
278
286
|
begin
|
279
|
-
select coalesce(acl_portal.event_id_of(_r), acl_portal.case_id_of(_r))
|
287
|
+
select coalesce(acl_portal.visit_id_of(_r), acl_portal.event_id_of(_r), acl_portal.case_id_of(_r))
|
280
288
|
into _id;
|
281
|
-
|
282
289
|
return _id;
|
283
290
|
end;
|
284
291
|
$$ language plpgsql
|
@@ -11,59 +11,128 @@ module MkAcl
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def generate
|
14
|
-
|
14
|
+
generate_user_role_functions
|
15
|
+
generate_current_role_functions
|
15
16
|
end
|
16
17
|
|
17
18
|
def self.generate(generator) self.new(generator).generate end
|
18
|
-
|
19
|
+
|
19
20
|
private
|
20
|
-
def
|
21
|
+
def generate_user_role_functions
|
21
22
|
# TODO: Test. Then combine with per-table methods
|
22
|
-
signature = "
|
23
|
+
signature = "#{acl_schema}.user_is_role(_user_id integer, _domain_id integer, _roles text[])"
|
23
24
|
puts %(
|
25
|
+
-- Return true if the user possess one or more of the given roles on the
|
26
|
+
-- domain record (cases, events, visits) with the given ID
|
27
|
+
--
|
24
28
|
drop function if exists #{signature} cascade;
|
25
29
|
create function #{signature} returns boolean as $$
|
26
|
-
select exists(
|
30
|
+
select exists (
|
27
31
|
select
|
28
32
|
from #{app_schema}.case_roles cr
|
29
33
|
join #{app_schema}.case_role_users cru on cru.case_role_id = cr.id
|
30
|
-
where cr.case_id =
|
31
|
-
and cru.user_id =
|
34
|
+
where cr.case_id = _domain_id
|
35
|
+
and cru.user_id = _user_id
|
36
|
+
and cr.kind = any(_roles)
|
37
|
+
|
38
|
+
union
|
39
|
+
|
40
|
+
select
|
41
|
+
from #{app_schema}.event_roles cr
|
42
|
+
join #{app_schema}.event_role_users cru on cru.event_role_id = cr.id
|
43
|
+
where cr.event_id = _domain_id
|
44
|
+
and cru.user_id = _user_id
|
32
45
|
and cr.kind = any(_roles)
|
46
|
+
|
47
|
+
union
|
48
|
+
|
49
|
+
select
|
50
|
+
from #{app_schema}.visit_roles cr
|
51
|
+
join #{app_schema}.visit_role_users cru on cru.visit_role_id = cr.id
|
52
|
+
where cr.visit_id = _domain_id
|
53
|
+
and cru.user_id = _user_id
|
54
|
+
and cr.kind = any(_roles)
|
55
|
+
|
33
56
|
);
|
34
57
|
$$ language sql
|
35
58
|
security definer;
|
36
59
|
).align
|
37
60
|
puts
|
38
61
|
|
39
|
-
signature = "
|
62
|
+
signature = "#{acl_schema}.user_is_role(_user_id integer, _domain_id integer, role text)"
|
63
|
+
puts %(
|
64
|
+
-- Return true if the user has the given role on the domain record
|
65
|
+
-- (cases, events, visits). Note that this function overloads the multi-role
|
66
|
+
-- version
|
67
|
+
--
|
68
|
+
drop function if exists #{signature} cascade;
|
69
|
+
create function #{signature} returns boolean as $$
|
70
|
+
select #{acl_schema}.user_is_role(_user_id, _domain_id, array[role]);
|
71
|
+
$$ language sql
|
72
|
+
security definer;
|
73
|
+
).align
|
74
|
+
puts
|
75
|
+
|
76
|
+
for domain, roles in DOMAINS.zip([CASE_ROLES, EVENT_ROLES, VISIT_ROLES])
|
77
|
+
for role in roles
|
78
|
+
signature = "#{acl_schema}.user_is_#{role.downcase}(_user_id integer, _domain_id integer)"
|
79
|
+
puts %(
|
80
|
+
-- Return true if the user possess the '#{role}' role
|
81
|
+
--
|
82
|
+
drop function if exists #{signature} cascade;
|
83
|
+
create function #{signature} returns boolean as $$
|
84
|
+
select #{acl_schema}.user_is_role(_user_id, _domain_id, '#{role}');
|
85
|
+
$$ language sql
|
86
|
+
security definer;
|
87
|
+
).align
|
88
|
+
puts
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_current_role_functions
|
94
|
+
# TODO: Test. Then combine with per-table methods
|
95
|
+
signature = "public.current_is_role(_domain_id integer, _roles text[])"
|
96
|
+
puts %(
|
97
|
+
-- Return true if the current user possess one or more of the given roles on the
|
98
|
+
-- domain record (cases, events, visits) with the given ID
|
99
|
+
--
|
100
|
+
drop function if exists #{signature} cascade;
|
101
|
+
create function #{signature} returns boolean as $$
|
102
|
+
select #{acl_schema}.user_is_role(public.current_user_id(), _domain_id, _roles);
|
103
|
+
$$ language sql
|
104
|
+
security definer;
|
105
|
+
).align
|
106
|
+
puts
|
107
|
+
|
108
|
+
signature = "public.current_is_role(_domain_id integer, _role text)"
|
40
109
|
puts %(
|
110
|
+
-- Return true if the current user possess the given role on the domain record
|
111
|
+
-- (cases, events, visits). Note that this function overloads the multi-role
|
112
|
+
-- version
|
113
|
+
--
|
41
114
|
drop function if exists #{signature} cascade;
|
42
115
|
create function #{signature} returns boolean as $$
|
43
|
-
select public.
|
116
|
+
select #{acl_schema}.user_is_role(public.current_user_id(), _domain_id, array[_role]);
|
44
117
|
$$ language sql
|
45
118
|
security definer;
|
46
119
|
).align
|
47
120
|
puts
|
48
121
|
|
49
|
-
for
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
$$ language sql
|
64
|
-
security definer;
|
65
|
-
).align
|
66
|
-
puts
|
122
|
+
for domain, roles in DOMAINS.zip([CASE_ROLES, EVENT_ROLES, VISIT_ROLES])
|
123
|
+
for role in roles
|
124
|
+
signature = "public.current_is_#{role.downcase}(_domain_id integer)"
|
125
|
+
puts %(
|
126
|
+
-- Return true if the current user possess the '#{role}' role
|
127
|
+
--
|
128
|
+
drop function if exists #{signature} cascade;
|
129
|
+
create function #{signature} returns boolean as $$
|
130
|
+
select #{acl_schema}.user_is_role(public.current_user_id(), _domain_id, '#{role}');
|
131
|
+
$$ language sql
|
132
|
+
security definer;
|
133
|
+
).align
|
134
|
+
puts
|
135
|
+
end
|
67
136
|
end
|
68
137
|
end
|
69
138
|
end
|
@@ -6,7 +6,7 @@ module MkAcl
|
|
6
6
|
# problem is that a record that fails the rule check is silently ignored
|
7
7
|
# which is probably not what you want
|
8
8
|
#
|
9
|
-
# The roles matches
|
9
|
+
# The roles matches an acl_* array against a role action entry in the spec
|
10
10
|
# file. The acl_* arrays are themselves array of role ids. Each subarray is
|
11
11
|
# indexed using the order in the acl.spec file
|
12
12
|
#
|
@@ -14,7 +14,7 @@ module MkAcl
|
|
14
14
|
def parse_spec
|
15
15
|
hash = YAML.load(IO.read(file), symbolize_names: true)
|
16
16
|
|
17
|
-
schema = hash.delete(:schema) or raise ArgumentError, "Can't find 'schema' declaration"
|
17
|
+
schema = hash.delete(:schema) or raise ArgumentError, "Can't find 'schema' declaration in #{file}"
|
18
18
|
app_schema = schema[:app] or raise ArgumentError, "Can't find 'schema.app' attribute"
|
19
19
|
acl_schema = schema[:acl] or raise ArgumentError, "Can't find 'schema.acl' attribute"
|
20
20
|
spec = Spec.new(file, app_schema, acl_schema)
|
data/lib/mikras_utils/mkacl.rb
CHANGED
@@ -9,7 +9,14 @@ require 'prick-inflector'
|
|
9
9
|
module MkAcl
|
10
10
|
class ParseError < RuntimeError; end
|
11
11
|
|
12
|
-
|
12
|
+
DOMAINS = %w(case event visit)
|
13
|
+
DOMAIN_TABLES = DOMAINS.map { "#{_1}s" }
|
14
|
+
|
15
|
+
CASE_ROLES = %w(LA TA KON AKK RLA CLA CTA)
|
16
|
+
EVENT_ROLES = %w(ELA ETA)
|
17
|
+
VISIT_ROLES = %w(VLA VTA)
|
18
|
+
|
19
|
+
ROLES = CASE_ROLES + EVENT_ROLES + VISIT_ROLES
|
13
20
|
end
|
14
21
|
|
15
22
|
require_relative 'mkacl/spec.rb'
|
data/lib/mikras_utils/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mikras_utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg_conn
|