50
50
)
51
51
from simcore_postgres_database .storage_models import file_meta_data , user_to_groups
52
52
from simcore_postgres_database .utils_repos import pass_or_acquire_connection
53
- from simcore_postgres_database .utils_sql import assemble_array_groups
54
53
from sqlalchemy .ext .asyncio import AsyncConnection
55
54
56
55
from ...exceptions .errors import InvalidFileIdentifierError
@@ -89,112 +88,104 @@ def _aggregate_access_rights(
89
88
return AccessRights .none ()
90
89
91
90
92
- access_rights_subquery = (
93
- sa .select (
94
- project_to_groups .c .project_uuid ,
95
- sa .func .jsonb_object_agg (
96
- project_to_groups .c .gid ,
97
- sa .func .jsonb_build_object (
98
- "read" ,
99
- project_to_groups .c .read ,
100
- "write" ,
101
- project_to_groups .c .write ,
102
- "delete" ,
103
- project_to_groups .c .delete ,
104
- ),
91
+ def my_private_workspace_access_rights_subquery (user_group_ids : list [GroupID ]):
92
+ return (
93
+ sa .select (
94
+ project_to_groups .c .project_uuid ,
95
+ sa .func .jsonb_object_agg (
96
+ project_to_groups .c .gid ,
97
+ sa .func .jsonb_build_object (
98
+ "read" ,
99
+ project_to_groups .c .read ,
100
+ "write" ,
101
+ project_to_groups .c .write ,
102
+ "delete" ,
103
+ project_to_groups .c .delete ,
104
+ ),
105
+ ).label ("access_rights" ),
106
+ )
107
+ .where (
108
+ (project_to_groups .c .read ) # Filters out entries where "read" is False
109
+ & (
110
+ project_to_groups .c .gid .in_ (user_group_ids )
111
+ ) # Filters gid to be in user_groups
105
112
)
106
- .filter (project_to_groups .c .read ) # Filters out entries where "read" is False
107
- .label ("access_rights" ),
108
- ).group_by (project_to_groups .c .project_uuid )
109
- ).subquery ("access_rights_subquery" )
110
-
111
-
112
- workspace_access_rights_subquery = (
113
- sa .select (
114
- workspaces_access_rights .c .workspace_id ,
115
- sa .func .jsonb_object_agg (
116
- workspaces_access_rights .c .gid ,
117
- sa .func .jsonb_build_object (
118
- "read" ,
119
- workspaces_access_rights .c .read ,
120
- "write" ,
121
- workspaces_access_rights .c .write ,
122
- "delete" ,
123
- workspaces_access_rights .c .delete ,
124
- ),
113
+ .group_by (project_to_groups .c .project_uuid )
114
+ ).subquery ("my_access_rights_subquery" )
115
+
116
+
117
+ def my_shared_workspace_access_rights_subquery (user_group_ids : list [GroupID ]):
118
+ return (
119
+ sa .select (
120
+ workspaces_access_rights .c .workspace_id ,
121
+ sa .func .jsonb_object_agg (
122
+ workspaces_access_rights .c .gid ,
123
+ sa .func .jsonb_build_object (
124
+ "read" ,
125
+ workspaces_access_rights .c .read ,
126
+ "write" ,
127
+ workspaces_access_rights .c .write ,
128
+ "delete" ,
129
+ workspaces_access_rights .c .delete ,
130
+ ),
131
+ ).label ("access_rights" ),
132
+ )
133
+ .where (
134
+ (
135
+ workspaces_access_rights .c .read
136
+ ) # Filters out entries where "read" is False
137
+ & (
138
+ workspaces_access_rights .c .gid .in_ (user_group_ids )
139
+ ) # Filters gid to be in user_groups
125
140
)
126
- .filter (workspaces_access_rights .c .read )
127
- .label ("access_rights" ),
128
- ).group_by (workspaces_access_rights .c .workspace_id )
129
- ).subquery ("workspace_access_rights_subquery" )
141
+ .group_by (workspaces_access_rights .c .workspace_id )
142
+ ).subquery ("my_workspace_access_rights_subquery" )
130
143
131
144
132
- async def _list_projects_access_rights (
145
+ async def _list_user_projects_access_rights_with_read_access (
133
146
connection : AsyncConnection , user_id : UserID
134
- ) -> dict [ProjectID , AccessRights ]:
147
+ ) -> list [ProjectID ]:
135
148
"""
136
149
Returns access-rights of user (user_id) over all OWNED or SHARED projects
137
150
"""
138
151
139
152
user_group_ids : list [GroupID ] = await _get_user_groups_ids (connection , user_id )
153
+ _my_access_rights_subquery = my_private_workspace_access_rights_subquery (
154
+ user_group_ids
155
+ )
140
156
141
157
private_workspace_query = (
142
158
sa .select (
143
159
projects .c .uuid ,
144
- access_rights_subquery .c .access_rights ,
145
- )
146
- .select_from (projects .join (access_rights_subquery , isouter = True ))
147
- .where (
148
- (
149
- (projects .c .prj_owner == user_id )
150
- | sa .text (
151
- f"jsonb_exists_any(access_rights_subquery.access_rights, { assemble_array_groups (user_group_ids )} )"
152
- )
153
- )
154
- & (projects .c .workspace_id .is_ (None ))
155
160
)
161
+ .select_from (projects .join (_my_access_rights_subquery ))
162
+ .where (projects .c .workspace_id .is_ (None ))
163
+ )
164
+
165
+ _my_workspace_access_rights_subquery = my_shared_workspace_access_rights_subquery (
166
+ user_group_ids
156
167
)
157
168
158
169
shared_workspace_query = (
159
- sa .select (
160
- projects .c .uuid ,
161
- workspace_access_rights_subquery .c .access_rights ,
162
- )
170
+ sa .select (projects .c .uuid )
163
171
.select_from (
164
172
projects .join (
165
- workspace_access_rights_subquery ,
173
+ _my_workspace_access_rights_subquery ,
166
174
projects .c .workspace_id
167
- == workspace_access_rights_subquery .c .workspace_id ,
175
+ == _my_workspace_access_rights_subquery .c .workspace_id ,
168
176
)
169
177
)
170
- .where (
171
- (
172
- sa .text (
173
- f"jsonb_exists_any(workspace_access_rights_subquery.access_rights, { assemble_array_groups (user_group_ids )} )"
174
- )
175
- )
176
- & (projects .c .workspace_id .is_not (None ))
177
- )
178
+ .where (projects .c .workspace_id .is_not (None ))
178
179
)
179
180
180
181
combined_query = sa .union_all (private_workspace_query , shared_workspace_query )
181
182
182
- projects_access_rights = {}
183
+ projects_access_rights = []
183
184
184
185
async for row in await connection .stream (combined_query ):
185
- assert isinstance (row .access_rights , dict ) # nosec
186
186
assert isinstance (row .uuid , str ) # nosec
187
187
188
- if row .access_rights :
189
- # NOTE: access_rights should be direclty filtered from result in stm instead calling again user_group_ids
190
- projects_access_rights [ProjectID (row .uuid )] = _aggregate_access_rights (
191
- row .access_rights , user_group_ids
192
- )
193
-
194
- else :
195
- # backwards compatibility
196
- # - no access_rights defined BUT project is owned
197
- projects_access_rights [ProjectID (row .uuid )] = AccessRights .all ()
188
+ projects_access_rights .append (ProjectID (row .uuid ))
198
189
199
190
return projects_access_rights
200
191
@@ -213,44 +204,40 @@ async def get_project_access_rights(
213
204
214
205
async with pass_or_acquire_connection (self .db_engine , connection ) as conn :
215
206
user_group_ids = await _get_user_groups_ids (conn , user_id )
207
+ _my_access_rights_subquery = my_private_workspace_access_rights_subquery (
208
+ user_group_ids
209
+ )
216
210
217
211
private_workspace_query = (
218
212
sa .select (
219
213
projects .c .prj_owner ,
220
- access_rights_subquery .c .access_rights ,
214
+ _my_access_rights_subquery .c .access_rights ,
221
215
)
222
- .select_from (projects .join (access_rights_subquery , isouter = True ))
216
+ .select_from (projects .join (_my_access_rights_subquery ))
223
217
.where (
224
218
(projects .c .uuid == f"{ project_id } " )
225
- & (
226
- (projects .c .prj_owner == user_id )
227
- | sa .text (
228
- f"jsonb_exists_any(access_rights_subquery.access_rights, { assemble_array_groups (user_group_ids )} )"
229
- )
230
- )
231
219
& (projects .c .workspace_id .is_ (None ))
232
220
)
233
221
)
234
222
223
+ _my_workspace_access_rights_subquery = (
224
+ my_shared_workspace_access_rights_subquery (user_group_ids )
225
+ )
226
+
235
227
shared_workspace_query = (
236
228
sa .select (
237
229
projects .c .prj_owner ,
238
- workspace_access_rights_subquery .c .access_rights ,
230
+ _my_workspace_access_rights_subquery .c .access_rights ,
239
231
)
240
232
.select_from (
241
233
projects .join (
242
- workspace_access_rights_subquery ,
234
+ _my_workspace_access_rights_subquery ,
243
235
projects .c .workspace_id
244
- == workspace_access_rights_subquery .c .workspace_id ,
236
+ == _my_workspace_access_rights_subquery .c .workspace_id ,
245
237
)
246
238
)
247
239
.where (
248
240
(projects .c .uuid == f"{ project_id } " )
249
- & (
250
- sa .text (
251
- f"jsonb_exists_any(workspace_access_rights_subquery.access_rights, { assemble_array_groups (user_group_ids )} )"
252
- )
253
- )
254
241
& (projects .c .workspace_id .is_not (None ))
255
242
)
256
243
)
@@ -358,5 +345,6 @@ async def get_readable_project_ids(
358
345
) -> list [ProjectID ]:
359
346
"""Returns a list of projects where user has granted read-access"""
360
347
async with pass_or_acquire_connection (self .db_engine , connection ) as conn :
361
- projects_access_rights = await _list_projects_access_rights (conn , user_id )
362
- return [pid for pid , access in projects_access_rights .items () if access .read ]
348
+ return await _list_user_projects_access_rights_with_read_access (
349
+ conn , user_id
350
+ )
0 commit comments