mikras_utils 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|