1
|
WITH RECURSIVE
|
2
|
project_subtree(uuid) as (
|
3
|
-- values ('x1u39-j7d0g-rufsjii9txtu2xg')
|
4
|
-- values ('x1u39-tpzed-fr97h9t4m5jffxs')
|
5
|
values ('x1u39-tpzed-3kz0nwtjehhl0u4')
|
6
|
union
|
7
|
select groups.uuid from groups join project_subtree on (groups.owner_uuid = project_subtree.uuid)
|
8
|
)
|
9
|
select uuid from project_subtree;
|
10
|
|
11
|
WITH RECURSIVE edges(tail_uuid, head_uuid) as (
|
12
|
select groups.owner_uuid, groups.uuid from groups
|
13
|
union
|
14
|
select links.tail_uuid, links.head_uuid from links
|
15
|
where links.link_class='permission'
|
16
|
),
|
17
|
project_subtree(uuid) as (
|
18
|
-- values ('x1u39-j7d0g-rufsjii9txtu2xg')
|
19
|
-- values ('x1u39-tpzed-fr97h9t4m5jffxs')
|
20
|
values ('x1u39-tpzed-3kz0nwtjehhl0u4')
|
21
|
union
|
22
|
(select edges.head_uuid from edges join project_subtree on (edges.tail_uuid = project_subtree.uuid)
|
23
|
))
|
24
|
select uuid from project_subtree;
|
25
|
|
26
|
|
27
|
WITH RECURSIVE perm_value(name, val) AS (
|
28
|
VALUES ('can_read'::text,(1)::smallint), ('can_login'::text,1), ('can_write'::text,2), ('can_manage'::text,3)
|
29
|
),
|
30
|
edges(tail_uuid, head_uuid, val) as (
|
31
|
select groups.owner_uuid, groups.uuid, (3) from groups
|
32
|
union
|
33
|
select links.tail_uuid, links.head_uuid, pv.val from links
|
34
|
JOIN perm_value pv ON ((pv.name = (links.name)::text))
|
35
|
where links.link_class='permission'
|
36
|
),
|
37
|
project_subtree(target_uuid, val) as (
|
38
|
-- values ('x1u39-j7d0g-rufsjii9txtu2xg')
|
39
|
-- values ('x1u39-tpzed-fr97h9t4m5jffxs')
|
40
|
values ('x1u39-tpzed-3kz0nwtjehhl0u4', 3)
|
41
|
union
|
42
|
(select edges.head_uuid, least(edges.val, project_subtree.val) from edges join project_subtree
|
43
|
on (edges.tail_uuid = project_subtree.target_uuid)
|
44
|
))
|
45
|
select target_uuid, val from project_subtree;
|
46
|
|
47
|
create table computed_permissions (
|
48
|
user_uuid character varying (27), target_uuid character varying (27), perm_level smallint);
|
49
|
create unique index computed_permissions_index on computed_permissions (user_uuid, target_uuid);
|
50
|
|
51
|
-- unique index on (user, target_uuid)
|
52
|
|
53
|
-- Permission in model:
|
54
|
-- tail (owner_uuid)
|
55
|
-- permission level
|
56
|
-- head (or uuid of new project or group)
|
57
|
|
58
|
-- Adding a permission
|
59
|
-- with recursive search from head, get affected nodes
|
60
|
-- next, select (users, permission) with target_uuid = tail (or owner_uuid)
|
61
|
-- insert \forall users \forall nodes (user, node, least(user perm, node perm))
|
62
|
-- on conflict update set greatest(existing perm, new perm)
|
63
|
|
64
|
-- Removing a permission
|
65
|
-- with recursive search from head, get affected nodes
|
66
|
-- delete all permissions with target_uuid in affected nodes
|
67
|
-- select permission links where
|
68
|
-- head is in the affected nodes
|
69
|
-- tail is in computed permissions
|
70
|
-- re-add each link (via adding a permission, above)
|
71
|
|
72
|
|
73
|
begin;
|
74
|
create TEMPORARY table affected_perms on commit drop
|
75
|
as WITH RECURSIVE perm_value(name, val) AS (
|
76
|
VALUES ('can_read'::text,(1)::smallint), ('can_login'::text,1), ('can_write'::text,2), ('can_manage'::text,3)
|
77
|
),
|
78
|
edges(tail_uuid, head_uuid, val) as (
|
79
|
select groups.owner_uuid, groups.uuid, (3) from groups
|
80
|
union
|
81
|
select links.tail_uuid, links.head_uuid, pv.val from links
|
82
|
JOIN perm_value pv ON ((pv.name = (links.name)::text))
|
83
|
where links.link_class='permission' and links.head_uuid not like '%-tpzed-%'
|
84
|
),
|
85
|
project_subtree(target_uuid, val) as (
|
86
|
-- values ('x1u39-j7d0g-rufsjii9txtu2xg')
|
87
|
-- values ('x1u39-tpzed-fr97h9t4m5jffxs')
|
88
|
-- values ('x1u39-j7d0g-qjt4uv6kq0ntm3y', 3)
|
89
|
values ('x1u39-tpzed-3kz0nwtjehhl0u4', 3)
|
90
|
union
|
91
|
(select edges.head_uuid, least(edges.val, project_subtree.val) from edges join project_subtree
|
92
|
on (edges.tail_uuid = project_subtree.target_uuid)))
|
93
|
select target_uuid, val from project_subtree;
|
94
|
|
95
|
select * from affected_perms;
|
96
|
|
97
|
insert into computed_permissions select 'x1u39-tpzed-3kz0nwtjehhl0u4', target_uuid, val from affected_perms;
|
98
|
|
99
|
delete from computed_permissions
|
100
|
where exists
|
101
|
(select 1 from affected_perms where
|
102
|
computed_permissions.user_uuid='x1u39-tpzed-3kz0nwtjehhl0u4'
|
103
|
and computed_permissions.target_uuid=affected_perms.target_uuid
|
104
|
and computed_permissions.val=affected_perms.val);
|
105
|
|
106
|
create TEMPORARY table links_to_recompute on commit drop
|
107
|
as WITH perm_value(name, val) AS (
|
108
|
VALUES ('can_read'::text,(1)::smallint), ('can_login'::text,1), ('can_write'::text,2), ('can_manage'::text,3)
|
109
|
)
|
110
|
select links.tail_uuid, links.head_uuid, pv.val from links
|
111
|
JOIN affected_perms on (links.head_uuid = affected_perms.target_uuid)
|
112
|
JOIN perm_value pv ON ((pv.name = (links.name)::text))
|
113
|
where links.link_class='permission';
|
114
|
|
115
|
select * from links_to_recompute;
|
116
|
|
117
|
commit;
|
118
|
|
119
|
create or replace function project_subtree (starting_uuid varchar(27))
|
120
|
returns table (target_uuid varchar(27))
|
121
|
STABLE
|
122
|
language SQL
|
123
|
as $$
|
124
|
WITH RECURSIVE
|
125
|
project_subtree(uuid) as (
|
126
|
values (starting_uuid)
|
127
|
union
|
128
|
select groups.uuid from groups join project_subtree on (groups.owner_uuid = project_subtree.uuid)
|
129
|
)
|
130
|
select uuid from project_subtree;
|
131
|
$$;
|
132
|
|
133
|
|
134
|
create or replace function search_permission_graph (starting_uuid varchar(27), starting_perm smallint)
|
135
|
returns table (target_uuid varchar(27), val smallint)
|
136
|
STABLE
|
137
|
language SQL
|
138
|
as $$
|
139
|
WITH RECURSIVE perm_value(name, val) AS (
|
140
|
VALUES ('can_read'::text,(1)::smallint), ('can_login'::text,1), ('can_write'::text,2), ('can_manage'::text,3)
|
141
|
),
|
142
|
edges(tail_uuid, head_uuid, val) as (
|
143
|
select groups.owner_uuid, groups.uuid, (3) from groups
|
144
|
union
|
145
|
select links.tail_uuid, links.head_uuid, pv.val from links
|
146
|
JOIN perm_value pv ON ((pv.name = (links.name)::text))
|
147
|
where links.link_class='permission'
|
148
|
),
|
149
|
project_subtree(target_uuid, val) as (
|
150
|
values (starting_uuid, starting_perm)
|
151
|
union
|
152
|
(select edges.head_uuid, least(edges.val, project_subtree.val)::smallint from edges join project_subtree
|
153
|
on (edges.tail_uuid = project_subtree.target_uuid)
|
154
|
where edges.tail_uuid like '_____-j7d0g-_______________'
|
155
|
or edges.tail_uuid = starting_uuid))
|
156
|
select target_uuid, max(val) from project_subtree
|
157
|
group by (target_uuid) ;
|
158
|
$$;
|
159
|
|
160
|
create or replace function add_permission (tail_uuid varchar(27), head_uuid varchar(27), perm_value smallint)
|
161
|
returns table(user_uuid character varying (27), target_uuid character varying (27), val smallint)
|
162
|
VOLATILE
|
163
|
language SQL
|
164
|
as $$
|
165
|
with
|
166
|
affected_nodes(target_uuid, val)
|
167
|
as (select target_uuid, val from search_permission_graph(head_uuid, perm_value)),
|
168
|
affected_users(user_uuid, val)
|
169
|
as (select user_uuid, perm_level from computed_permissions where target_uuid = tail_uuid),
|
170
|
new_perms(user_uuid, target_uuid, val)
|
171
|
as (select affected_users.user_uuid, affected_nodes.target_uuid, least(affected_nodes.val, affected_users.val)
|
172
|
from affected_nodes cross join affected_users)
|
173
|
insert into computed_permissions (user_uuid, target_uuid, perm_level)
|
174
|
(select user_uuid, target_uuid, val from new_perms)
|
175
|
on conflict (user_uuid, target_uuid) do update set perm_level=greatest(computed_permissions.perm_level, excluded.perm_level)
|
176
|
returning *;
|
177
|
$$;
|
178
|
|
179
|
create or replace function clear_permission (head_uuid varchar(27))
|
180
|
returns table(user_uuid character varying (27), target_uuid character varying (27), val smallint)
|
181
|
VOLATILE
|
182
|
language SQL
|
183
|
as $$
|
184
|
with
|
185
|
affected_nodes(target_uuid)
|
186
|
as (select target_uuid from search_permission_graph(head_uuid, 0::smallint))
|
187
|
delete from computed_permissions where
|
188
|
target_uuid in (select target_uuid from affected_nodes where target_uuid <> user_uuid)
|
189
|
returning *;
|
190
|
$$;
|
191
|
|
192
|
|
193
|
create or replace function remove_permission_helper (starting_uuid varchar(27))
|
194
|
returns table(link_uuid character varying (27), tail_uuid character varying (27), head_uuid character varying (27), val smallint)
|
195
|
VOLATILE
|
196
|
language SQL
|
197
|
as $$
|
198
|
with perm_value(name, val) AS (
|
199
|
VALUES ('can_read'::text,(1)::smallint), ('can_login'::text,1), ('can_write'::text,2), ('can_manage'::text,3)),
|
200
|
removed_rows(user_uuid, target_uuid, val) as (
|
201
|
select user_uuid, target_uuid, val from clear_permission(starting_uuid))
|
202
|
select links.uuid, links.tail_uuid, links.head_uuid, pv.val::smallint from links
|
203
|
JOIN perm_value pv ON ((pv.name = (links.name)::text))
|
204
|
where links.link_class='permission' and
|
205
|
exists (select 1 from computed_permissions where
|
206
|
links.tail_uuid=computed_permissions.target_uuid) and
|
207
|
exists (select 1 from removed_rows where links.head_uuid=removed_rows.target_uuid)
|
208
|
$$;
|
209
|
|
210
|
create or replace function delete_permission_link (link_uuid varchar(27), link_head_uuid varchar(27))
|
211
|
returns table(tail_uuid character varying (27), head_uuid character varying (27), val smallint)
|
212
|
VOLATILE
|
213
|
language SQL
|
214
|
as $$
|
215
|
with links_to_recompute(link_uuid, tail_uuid, head_uuid, val) as
|
216
|
(select * from remove_permission_helper(link_head_uuid)),
|
217
|
_delete_link as (delete from links where links.uuid=link_uuid)
|
218
|
select ap.user_uuid, ap.target_uuid, ap.val
|
219
|
from links_to_recompute,
|
220
|
lateral add_permission(links_to_recompute.tail_uuid, links_to_recompute.head_uuid, links_to_recompute.val::smallint) ap
|
221
|
where links_to_recompute.link_uuid <> link_uuid
|
222
|
$$;
|
223
|
|
224
|
create or replace function delete_group (group_uuid varchar(27))
|
225
|
returns table(tail_uuid character varying (27), head_uuid character varying (27), val smallint)
|
226
|
VOLATILE
|
227
|
language SQL
|
228
|
as $$
|
229
|
with links_to_recompute(link_uuid, tail_uuid, head_uuid, val) as
|
230
|
(select * from remove_permission_helper(group_uuid)),
|
231
|
_delete_group as (delete from groups where groups.uuid=group_uuid)
|
232
|
select ap.user_uuid, ap.target_uuid, ap.val
|
233
|
from links_to_recompute,
|
234
|
lateral add_permission(links_to_recompute.tail_uuid, links_to_recompute.head_uuid, links_to_recompute.val::smallint) ap
|
235
|
$$;
|
236
|
|
237
|
create or replace function move_group (group_uuid varchar(27), new_owner_uuid varchar(27))
|
238
|
returns table(tail_uuid character varying (27), head_uuid character varying (27), val smallint)
|
239
|
VOLATILE
|
240
|
language SQL
|
241
|
as $$
|
242
|
with links_to_recompute(link_uuid, tail_uuid, head_uuid, val) as
|
243
|
(values ('', new_owner_uuid, group_uuid, 3::smallint)
|
244
|
union
|
245
|
select link_uuid, tail_uuid, head_uuid, val from remove_permission_helper(group_uuid)),
|
246
|
update_group as (update groups set owner_uuid=new_owner_uuid where groups.uuid=group_uuid)
|
247
|
select ap.user_uuid, ap.target_uuid, ap.val
|
248
|
from links_to_recompute,
|
249
|
lateral add_permission(links_to_recompute.tail_uuid, links_to_recompute.head_uuid, links_to_recompute.val::smallint) ap
|
250
|
$$;
|
251
|
|
252
|
|
253
|
|
254
|
insert into computed_permissions (user_uuid, target_uuid, perm_level) values ('x1u39-tpzed-3kz0nwtjehhl0u4', 'x1u39-tpzed-3kz0nwtjehhl0u4', 3);
|
255
|
|
256
|
select * from add_permission('x1u39-tpzed-3kz0nwtjehhl0u4', 'x1u39-tpzed-3kz0nwtjehhl0u4', 3::smallint);
|
257
|
|
258
|
-- x1u39-j7d0g-sh5mwu9t8b71al6 -> Project under old user (owned by x1u39-j7d0g-7mj64tj4fe3snmo)
|
259
|
-- x1u39-j7d0g-qjt4uv6kq0ntm3y -> Foghord (can_write x1u39-j7d0g-7mj64tj4fe3snmo) (can_read x1u39-tpzed-3kz0nwtjehhl0u4)
|
260
|
-- x1u39-j7d0g-sij00wivb8v3hkt -> Thinger holder (owned by x1u39-tpzed-3kz0nwtjehhl0u4)
|
261
|
-- x1u39-j7d0g-7mj64tj4fe3snmo -> Data from old user
|
262
|
-- x1u39-tpzed-3kz0nwtjehhl0u4 -> c c (can_manage x1u39-j7d0g-qjt4uv6kq0ntm3y)
|