mikras_utils 0.1.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 +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +10 -0
- data/README.md +31 -0
- data/Rakefile +8 -0
- data/acl-build +5 -0
- data/build +11 -0
- data/exe/mikras_utils +5 -0
- data/exe/mkacl +59 -0
- data/lib/mikras_utils/mkacl/analyzer.rb +46 -0
- data/lib/mikras_utils/mkacl/generator.rb +55 -0
- data/lib/mikras_utils/mkacl/generators/acl_functions.rb +208 -0
- data/lib/mikras_utils/mkacl/generators/id_functions.rb +262 -0
- data/lib/mikras_utils/mkacl/generators/insert_triggers.rb +267 -0
- data/lib/mikras_utils/mkacl/generators/role_functions.rb +72 -0
- data/lib/mikras_utils/mkacl/generators/rules.rb +80 -0
- data/lib/mikras_utils/mkacl/parser.rb +73 -0
- data/lib/mikras_utils/mkacl/spec.rb +154 -0
- data/lib/mikras_utils/mkacl.rb +18 -0
- data/lib/mikras_utils/version.rb +5 -0
- data/lib/mikras_utils.rb +6 -0
- data/sig/mikras_utils.rbs +4 -0
- data/tests/acl.fox +312 -0
- data/tests/acl.spec +135 -0
- data/tests/acl.sql +132 -0
- data/tests/acl_portal-functions.sql +94 -0
- data/tests/acl_portal-tables.sql +23 -0
- data/tests/acl_portal-views.sql +73 -0
- data/tests/agg.sql +25 -0
- data/tests/app.sql +48 -0
- data/tests/app_portal-tables.sql +138 -0
- data/tests/app_portal-triggers.sql +23 -0
- data/tests/app_portal-views.sql +203 -0
- data/tests/auth.sql +12 -0
- data/tests/auth.users.sql +5 -0
- data/tests/build +7 -0
- data/tests/final-functions.sql +28 -0
- data/tests/fox.sql +158 -0
- data/tests/initial-functions.sql +6 -0
- data/tests/meta.sql +197 -0
- data/tests/reflections.yml +5 -0
- data/tests/schemas.sql +25 -0
- data/tests/setup.sql +8 -0
- data/tests/sys_portal.sql +172 -0
- metadata +145 -0
data/tests/acl.sql
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
drop schema if exists acl cascade;
|
4
|
+
create schema acl;
|
5
|
+
set search_path to acl;
|
6
|
+
|
7
|
+
create view tables as
|
8
|
+
select distinct
|
9
|
+
schema_name,
|
10
|
+
table_name
|
11
|
+
from
|
12
|
+
meta.columns
|
13
|
+
where
|
14
|
+
column_name like 'acl\_%'
|
15
|
+
;
|
16
|
+
|
17
|
+
\echo ACL_TABLES
|
18
|
+
select * from tables where schema_name = 'app_portal';
|
19
|
+
|
20
|
+
create view schemas as
|
21
|
+
select distinct
|
22
|
+
schema_name
|
23
|
+
from
|
24
|
+
tables
|
25
|
+
;
|
26
|
+
|
27
|
+
-- Subset of meta.columns where both referencing and referenced tables are ACL tables
|
28
|
+
drop view if exists links cascade;
|
29
|
+
create view links as
|
30
|
+
select c.*
|
31
|
+
from tables tf
|
32
|
+
join meta.links c
|
33
|
+
on c.schema_name = tf.schema_name
|
34
|
+
and c.table_name = tf.table_name
|
35
|
+
join tables tt
|
36
|
+
on tt.schema_name = c.ref_schema_name
|
37
|
+
and tt.table_name = c.ref_table_name
|
38
|
+
;
|
39
|
+
|
40
|
+
\echo ACL_LINKS
|
41
|
+
select * from links where schema_name = 'app_portal';
|
42
|
+
|
43
|
+
-- Subset of meta.chains where first and last table are ACL tables
|
44
|
+
drop view if exists chains cascade;
|
45
|
+
create view chains as
|
46
|
+
select mc.*
|
47
|
+
from meta.chains mc
|
48
|
+
join tables src on
|
49
|
+
mc.src_schema_name = src.schema_name
|
50
|
+
and mc.src_table_name = src.table_name
|
51
|
+
join tables dst on
|
52
|
+
mc.dst_schema_name = dst.schema_name
|
53
|
+
and mc.dst_table_name = dst.table_name
|
54
|
+
;
|
55
|
+
|
56
|
+
\echo ACL_CHAINS
|
57
|
+
--select * from chains where src_schema_name = 'app_portal';
|
58
|
+
|
59
|
+
drop view if exists closures cascade;
|
60
|
+
create view closures as
|
61
|
+
select
|
62
|
+
at.schema_name,
|
63
|
+
at.table_name,
|
64
|
+
coalesce(
|
65
|
+
array_agg(ac.src_schema_name || '.' || ac.src_table_name) filter (where ac.src_schema_name is not null),
|
66
|
+
array[]::varchar[]
|
67
|
+
) as closure_uids
|
68
|
+
from
|
69
|
+
tables at
|
70
|
+
left join chains ac
|
71
|
+
on ac.dst_schema_name = at.schema_name
|
72
|
+
and ac.dst_table_name = at.table_name
|
73
|
+
group by
|
74
|
+
at.schema_name,
|
75
|
+
at.table_name
|
76
|
+
;
|
77
|
+
|
78
|
+
\echo ACL_CLOSURES
|
79
|
+
--select * from closures;
|
80
|
+
|
81
|
+
drop view if exists paths cascade;
|
82
|
+
create view paths as
|
83
|
+
with
|
84
|
+
recursive search_path as (
|
85
|
+
with edges as (
|
86
|
+
select distinct
|
87
|
+
schema_name || '.' || table_name as "from_table",
|
88
|
+
ref_schema_name || '.' || ref_table_name as "to_table",
|
89
|
+
column_name as "from_column",
|
90
|
+
ref_column_name as "to_column"
|
91
|
+
from
|
92
|
+
acl.links
|
93
|
+
)
|
94
|
+
|
95
|
+
-- Anchor member: start from the initial node
|
96
|
+
select
|
97
|
+
from_table as "start_table",
|
98
|
+
from_table,
|
99
|
+
to_table,
|
100
|
+
array[from_table] as path,
|
101
|
+
array[array[from_table || '.' || from_column, to_table || '.' || to_column]] as link,
|
102
|
+
false as cycle
|
103
|
+
from edges
|
104
|
+
|
105
|
+
union all
|
106
|
+
|
107
|
+
-- Recursive member: find the next links
|
108
|
+
select
|
109
|
+
sp.start_table,
|
110
|
+
e.from_table,
|
111
|
+
e.to_table,
|
112
|
+
sp.path || e.from_table as "path",
|
113
|
+
sp.link || array[array[e.from_table || '.' || e.from_column, e.to_table || '.' || e.to_column]] as "link",
|
114
|
+
e.from_table = any(sp.path) as "cycle"
|
115
|
+
from search_path sp
|
116
|
+
join edges e on e.from_table = sp.to_table
|
117
|
+
where not sp.cycle
|
118
|
+
)
|
119
|
+
select
|
120
|
+
start_table,
|
121
|
+
to_table as "stop_table",
|
122
|
+
path || to_table as "path",
|
123
|
+
link as "links"
|
124
|
+
from search_path
|
125
|
+
order by
|
126
|
+
start_table,
|
127
|
+
"stop_table"
|
128
|
+
;
|
129
|
+
|
130
|
+
\echo ACL_PATHS
|
131
|
+
--select * from paths;
|
132
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
set search_path to acl_portal, public;
|
4
|
+
|
5
|
+
drop function if exists delete_user_acl(_user_id integer) cascade;
|
6
|
+
drop function if exists update_user_acl(_user_id integer) cascade;
|
7
|
+
drop function if exists create_user_acl(_user_id integer) cascade;
|
8
|
+
drop function if exists select_user_acl(_user_id integer) cascade;
|
9
|
+
drop function if exists create_user_acls() cascade;
|
10
|
+
|
11
|
+
-- Compute new ACLs for the given user and insert them into user_acls. It is an
|
12
|
+
-- error if the user already has a record there
|
13
|
+
create function create_user_acl(_user_id integer) returns integer[] as $$
|
14
|
+
with
|
15
|
+
agg_domain_users as (
|
16
|
+
select
|
17
|
+
user_id as "role_id",
|
18
|
+
array_agg(domain_role_id) as "role_ids"
|
19
|
+
from acl_portal.domain_users
|
20
|
+
group by "role_id"
|
21
|
+
)
|
22
|
+
insert into user_acls (user_id, role_ids)
|
23
|
+
select
|
24
|
+
_user_id,
|
25
|
+
esr.system_role_ids || adu.role_ids as "role_ids"
|
26
|
+
from
|
27
|
+
agg.effective_system_roles esr
|
28
|
+
left join agg_domain_users adu on adu.role_id = esr.role_id
|
29
|
+
where esr.role_id = _user_id
|
30
|
+
returning role_ids;
|
31
|
+
$$ language sql
|
32
|
+
set search_path from current;
|
33
|
+
|
34
|
+
-- Remove a user's ACL record in user_acls. It is not an error if the record
|
35
|
+
-- doesn't exist. The function can be used to immediately block a user from
|
36
|
+
-- accessing the system without going through all the user's assignments
|
37
|
+
create function delete_user_acl(_user_id integer) returns boolean as $$
|
38
|
+
delete from user_acls where user_id = _user_id returning true;
|
39
|
+
$$ language sql
|
40
|
+
set search_path from current;
|
41
|
+
|
42
|
+
-- Update a user's ACL record. It is not an error if the record doesn't exist
|
43
|
+
create function update_user_acl(_user_id integer) returns boolean as $$
|
44
|
+
begin
|
45
|
+
perform delete_user_acl(_user_id);
|
46
|
+
perform create_user_acl(_user_id);
|
47
|
+
return true;
|
48
|
+
end;
|
49
|
+
$$ language plpgsql
|
50
|
+
set search_path from current;
|
51
|
+
|
52
|
+
-- Find a user's ACL list. If the record doesn't exist, it is created before
|
53
|
+
-- the ACL list is returned to the caller. This function is also called from
|
54
|
+
-- the various policy rules and matched against the current record's access ACL
|
55
|
+
-- list so it has to be fast
|
56
|
+
--
|
57
|
+
-- It is marked 'stable' which is a blatant lie because it _does_ change the
|
58
|
+
-- database but this is ok because it will only change on for access
|
59
|
+
--
|
60
|
+
create function select_user_acl(_user_id integer) returns integer[] as $$
|
61
|
+
declare
|
62
|
+
_role_ids integer[];
|
63
|
+
begin
|
64
|
+
select role_ids
|
65
|
+
into _role_ids
|
66
|
+
from user_acls
|
67
|
+
where user_id = _user_id;
|
68
|
+
|
69
|
+
if not found then
|
70
|
+
select create_user_acl(_user_id)
|
71
|
+
into _role_ids
|
72
|
+
;
|
73
|
+
end if;
|
74
|
+
|
75
|
+
return _role_ids;
|
76
|
+
end;
|
77
|
+
$$ language plpgsql
|
78
|
+
stable
|
79
|
+
leakproof
|
80
|
+
security definer
|
81
|
+
set search_path from current;
|
82
|
+
|
83
|
+
-- Create or update all user's ACL lists. It is used after import of Sagsys
|
84
|
+
-- data
|
85
|
+
create function update_user_acls() returns boolean as $$
|
86
|
+
begin
|
87
|
+
delete from user_acls;
|
88
|
+
perform create_user_acl(id) from auth.users;
|
89
|
+
return true;
|
90
|
+
end;
|
91
|
+
$$ language plpgsql
|
92
|
+
set search_path from current;
|
93
|
+
|
94
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
drop table if exists acl_portal.attach_acls cascade;
|
4
|
+
create table acl_portal.attach_acls (
|
5
|
+
id integer generated by default as identity primary key,
|
6
|
+
parent_table varchar not null,
|
7
|
+
parent_id integer not null,
|
8
|
+
child_table varchar not null,
|
9
|
+
child_field varchar not null,
|
10
|
+
acls integer[] not null,
|
11
|
+
|
12
|
+
unique (child_table, child_field, parent_table, parent_id, acls)
|
13
|
+
);
|
14
|
+
|
15
|
+
-- Acts as a materialized view. A user's record is updated whenever case_users
|
16
|
+
-- or event_users are changed
|
17
|
+
drop table if exists acl_portal.user_acls cascade;
|
18
|
+
create table acl_portal.user_acls (
|
19
|
+
id integer generated by default as identity primary key,
|
20
|
+
user_id integer not null references auth.users(id) unique,
|
21
|
+
role_ids integer[] not null
|
22
|
+
);
|
23
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
/*
|
3
|
+
-- View of role kind id, domain id, role. Because case id and event id belongs
|
4
|
+
-- to the same namespace you can simply do
|
5
|
+
--
|
6
|
+
-- select * from domain_roles where id = ID' to get the roles of a domain object
|
7
|
+
--
|
8
|
+
drop view if exists acl_portal.domain_roles cascade;
|
9
|
+
create view acl_portal.domain_roles as
|
10
|
+
with
|
11
|
+
case_objects as (
|
12
|
+
select id, case_id as domain_id, role
|
13
|
+
from app_portal.case_roles cr
|
14
|
+
where role in ('CLA', 'CTA', 'KON', 'AKK')
|
15
|
+
),
|
16
|
+
event_objects as (
|
17
|
+
select er.id, e.id as domain_id, er.role
|
18
|
+
from app_portal.event_roles er
|
19
|
+
join app_portal.events e on e.id = er.event_id
|
20
|
+
where er.role in ('ELA', 'ETA')
|
21
|
+
)
|
22
|
+
select * from case_objects
|
23
|
+
union
|
24
|
+
select * from event_objects
|
25
|
+
union
|
26
|
+
select co.id, eo.domain_id, co.role
|
27
|
+
from event_objects eo
|
28
|
+
join app_portal.events e on e.id = eo.domain_id
|
29
|
+
join case_objects co on co.domain_id = e.case_id
|
30
|
+
order by
|
31
|
+
domain_id,
|
32
|
+
role
|
33
|
+
;
|
34
|
+
|
35
|
+
\echo DOMAIN_ROLES
|
36
|
+
select * from acl_portal.domain_roles;
|
37
|
+
|
38
|
+
-- TODO A LOT (automatically detect CLA, CTA)
|
39
|
+
drop view if exists acl_portal.domain_users cascade;
|
40
|
+
create view acl_portal.domain_users as
|
41
|
+
with
|
42
|
+
case_role_users as (
|
43
|
+
select
|
44
|
+
cr.id as "domain_role_id",
|
45
|
+
cu.user_id,
|
46
|
+
cr.role
|
47
|
+
from app_portal.case_users cu
|
48
|
+
join app_portal.case_roles cr on cr.id = cu.case_role_id
|
49
|
+
join app_portal.cases c on c.id = cr.case_id
|
50
|
+
where (not c.closed or cr.role in ('CLA', 'ELA'))
|
51
|
+
and cr.role in ('CLA', 'CTA', 'KON', 'AKK')
|
52
|
+
),
|
53
|
+
event_role_users as (
|
54
|
+
select
|
55
|
+
er.id as "domain_role_id",
|
56
|
+
eu.user_id,
|
57
|
+
er.role
|
58
|
+
from app_portal.event_users eu
|
59
|
+
join app_portal.event_roles er on er.id = eu.event_role_id
|
60
|
+
join app_portal.events e on e.id = er.event_id
|
61
|
+
where not e.closed or er.role in ('CLA', 'ELA')
|
62
|
+
)
|
63
|
+
select * from case_role_users
|
64
|
+
union
|
65
|
+
select * from event_role_users
|
66
|
+
order by
|
67
|
+
"domain_role_id",
|
68
|
+
"user_id"
|
69
|
+
;
|
70
|
+
|
71
|
+
\echo DOMAIN_USERS
|
72
|
+
select * from acl_portal.domain_users;
|
73
|
+
*/
|
data/tests/agg.sql
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
drop schema if exists agg cascade;
|
4
|
+
create schema agg;
|
5
|
+
|
6
|
+
drop table if exists agg.effective_system_roles;
|
7
|
+
create table agg.effective_system_roles (
|
8
|
+
role_id integer not null primary key,
|
9
|
+
system_role_ids integer[] not null
|
10
|
+
);
|
11
|
+
|
12
|
+
insert into agg.effective_system_roles(role_id, system_role_ids) values
|
13
|
+
(1, array[1]),
|
14
|
+
(2, array[2, 1]),
|
15
|
+
(3, array[3, 1]),
|
16
|
+
(4, array[4, 1]),
|
17
|
+
(5, array[5, 1000]),
|
18
|
+
(6, array[6, 2000]),
|
19
|
+
(7, array[7, 2001]),
|
20
|
+
(8, array[8, 2000]),
|
21
|
+
(9, array[9, 2001]),
|
22
|
+
(10, array[10, 2000]),
|
23
|
+
(11, array[11, 2001])
|
24
|
+
;
|
25
|
+
|
data/tests/app.sql
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
\i schemas.sql
|
4
|
+
\i meta.sql
|
5
|
+
\i acl.sql
|
6
|
+
\i auth.sql
|
7
|
+
\i agg.sql
|
8
|
+
|
9
|
+
\i initial-functions.sql
|
10
|
+
|
11
|
+
\i app_portal-tables.sql
|
12
|
+
\i app_portal-views.sql
|
13
|
+
\i acl_portal-tables.sql
|
14
|
+
\i acl_portal-views.sql
|
15
|
+
\i acl_portal-functions.sql
|
16
|
+
\i app_portal-triggers.sql
|
17
|
+
\i sys_portal.sql
|
18
|
+
|
19
|
+
\i final-functions.sql
|
20
|
+
|
21
|
+
set search_path to acl_portal, app_portal, sys_portal;
|
22
|
+
|
23
|
+
/*
|
24
|
+
\echo INCLUDING ACL-FUNCTIONS.SQL
|
25
|
+
\i acl-functions.sql
|
26
|
+
|
27
|
+
\echo INCLUDING ACL-META.SQL
|
28
|
+
\i acl-meta.sql
|
29
|
+
|
30
|
+
\echo INCLUDING ACL-ACL.sql
|
31
|
+
\i acl-acl.sql
|
32
|
+
|
33
|
+
\echo INCLUDING ACL-ACL_PORTAL.SQL
|
34
|
+
\i acl-acl_portal.sql
|
35
|
+
|
36
|
+
\echo INCLUDING ACL-SYS_PORTAL.SQL
|
37
|
+
\i acl-sys_portal.sql
|
38
|
+
|
39
|
+
\echo INCLUDING ACL-DOMAINS.SQL
|
40
|
+
\i acl-domains.sql
|
41
|
+
|
42
|
+
\echo INCLUDING ACL-FINAL_FUNCTIONS
|
43
|
+
\i acl-final_functions.sql
|
44
|
+
|
45
|
+
\echo ACLS
|
46
|
+
select * from agg_acl_users;
|
47
|
+
*/
|
48
|
+
|
@@ -0,0 +1,138 @@
|
|
1
|
+
\set ON_ERROR_STOP on
|
2
|
+
|
3
|
+
set search_path to app_portal;
|
4
|
+
|
5
|
+
-- Abstract base table for cases and events
|
6
|
+
create table abstract_domain_objects (
|
7
|
+
id integer generated by default as identity primary key
|
8
|
+
);
|
9
|
+
|
10
|
+
create table cases (
|
11
|
+
id integer not null references abstract_domain_objects(id) primary key,
|
12
|
+
name varchar,
|
13
|
+
ident varchar generated always as (name) stored,
|
14
|
+
closed boolean default false,
|
15
|
+
acl_select integer[],
|
16
|
+
acl_update integer[],
|
17
|
+
acl_delete integer[]
|
18
|
+
);
|
19
|
+
|
20
|
+
create table role_kinds (
|
21
|
+
id integer generated by default as identity primary key,
|
22
|
+
kind varchar not null unique,
|
23
|
+
acl boolean not null default false,
|
24
|
+
ordinal integer
|
25
|
+
);
|
26
|
+
|
27
|
+
-- Abstract base table for case_roles and event_roles
|
28
|
+
create table abstract_roles (
|
29
|
+
id integer generated by default as identity primary key
|
30
|
+
);
|
31
|
+
|
32
|
+
create table case_role_templates (
|
33
|
+
id integer primary key references abstract_roles(id),
|
34
|
+
"role" varchar not null references role_kinds(kind)
|
35
|
+
);
|
36
|
+
|
37
|
+
create table case_roles (
|
38
|
+
id integer primary key references abstract_roles(id),
|
39
|
+
case_id integer not null references cases(id),
|
40
|
+
"role" varchar not null references role_kinds(kind),
|
41
|
+
acl_select integer[],
|
42
|
+
acl_update integer[],
|
43
|
+
acl_delete integer[],
|
44
|
+
|
45
|
+
unique (case_id, "role")
|
46
|
+
);
|
47
|
+
|
48
|
+
create table case_users (
|
49
|
+
id integer generated by default as identity primary key,
|
50
|
+
case_role_id integer not null references case_roles(id),
|
51
|
+
user_id integer not null references auth.roles(id),
|
52
|
+
acl_select integer[],
|
53
|
+
acl_update integer[],
|
54
|
+
acl_delete integer[]
|
55
|
+
);
|
56
|
+
|
57
|
+
create table events (
|
58
|
+
id integer not null references abstract_domain_objects(id) primary key,
|
59
|
+
case_id integer not null references cases(id),
|
60
|
+
name varchar,
|
61
|
+
label varchar generated always as (name) stored,
|
62
|
+
closed boolean default false,
|
63
|
+
deleted boolean default false,
|
64
|
+
acl_select integer[],
|
65
|
+
acl_update integer[],
|
66
|
+
acl_delete integer[]
|
67
|
+
);
|
68
|
+
|
69
|
+
create table event_role_templates (
|
70
|
+
id integer primary key references abstract_roles(id),
|
71
|
+
"role" varchar not null references role_kinds(kind)
|
72
|
+
);
|
73
|
+
|
74
|
+
create table event_roles (
|
75
|
+
id integer primary key references abstract_roles(id),
|
76
|
+
event_id integer not null references events(id),
|
77
|
+
"role" varchar not null references role_kinds(kind),
|
78
|
+
acl_select integer[],
|
79
|
+
acl_update integer[],
|
80
|
+
acl_delete integer[],
|
81
|
+
|
82
|
+
unique(event_id, "role")
|
83
|
+
);
|
84
|
+
|
85
|
+
create table event_users (
|
86
|
+
id integer generated by default as identity primary key,
|
87
|
+
event_role_id integer not null references event_roles(id),
|
88
|
+
user_id integer not null references auth.roles(id),
|
89
|
+
acl_select integer[],
|
90
|
+
acl_update integer[],
|
91
|
+
acl_delete integer[]
|
92
|
+
);
|
93
|
+
|
94
|
+
create table bookings (
|
95
|
+
id integer generated by default as identity primary key,
|
96
|
+
event_id integer not null references events(id),
|
97
|
+
acl_select integer[],
|
98
|
+
acl_update integer[],
|
99
|
+
acl_delete integer[]
|
100
|
+
);
|
101
|
+
|
102
|
+
create table user_bookings (
|
103
|
+
id integer generated by default as identity primary key,
|
104
|
+
user_id integer not null references auth.roles(id),
|
105
|
+
booking_id integer not null references bookings(id),
|
106
|
+
acl_select integer[],
|
107
|
+
acl_update integer[],
|
108
|
+
acl_delete integer[]
|
109
|
+
);
|
110
|
+
|
111
|
+
create table visits (
|
112
|
+
id integer generated by default as identity primary key,
|
113
|
+
event_id integer not null references events(id),
|
114
|
+
name varchar,
|
115
|
+
acl_select integer[],
|
116
|
+
acl_update integer[],
|
117
|
+
acl_delete integer[]
|
118
|
+
);
|
119
|
+
|
120
|
+
create table noncompliances (
|
121
|
+
id integer generated by default as identity primary key,
|
122
|
+
visit_id integer not null references visits(id),
|
123
|
+
name varchar,
|
124
|
+
acl_select integer[],
|
125
|
+
acl_update integer[],
|
126
|
+
acl_delete integer[]
|
127
|
+
);
|
128
|
+
|
129
|
+
create table noncompliance_uploads (
|
130
|
+
id integer generated by default as identity primary key,
|
131
|
+
noncompliance_id integer not null references noncompliances(id),
|
132
|
+
name varchar,
|
133
|
+
uploaded_by_id integer not null references auth.roles(id),
|
134
|
+
acl_select integer[],
|
135
|
+
acl_update integer[],
|
136
|
+
acl_delete integer[]
|
137
|
+
);
|
138
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
--
|
3
|
+
-- Triggers that maintains acl_portal.user_acls.
|
4
|
+
--
|
5
|
+
|
6
|
+
-- Call acl_portal.update_user_acl on any change to either case_users or
|
7
|
+
-- event_users. Note that this function is both cross-table and cross
|
8
|
+
-- insert/delete
|
9
|
+
create function domain_users_aiud() returns trigger as $$
|
10
|
+
begin
|
11
|
+
perform acl_portal.update_user_acl(coalesce(NEW.user_id, OLD.user_id));
|
12
|
+
return null; -- works because this is an after-trigger
|
13
|
+
end;
|
14
|
+
$$ language plpgsql;
|
15
|
+
|
16
|
+
create trigger case_users_aiud_trg after insert or update or delete on app_portal.case_users
|
17
|
+
for each row execute function domain_users_aiud()
|
18
|
+
;
|
19
|
+
|
20
|
+
create trigger event_users_aiud_trg after insert or update or delete on app_portal.event_users
|
21
|
+
for each row execute function domain_users_aiud()
|
22
|
+
;
|
23
|
+
|