1- import sqlalchemy
1+ import sqlalchemy as sa
2+ from aiohttp import web
23from aiopg .sa .engine import Engine
3- from models_library .projects import ProjectID
4+ from models_library .groups import GroupID
5+ from models_library .projects import ProjectID , ProjectIDStr
46from models_library .users import UserID
7+ from models_library .workspaces import WorkspaceID
8+ from simcore_postgres_database .models .project_to_groups import project_to_groups
59from simcore_postgres_database .models .projects import projects
10+ from simcore_postgres_database .models .workspaces_access_rights import (
11+ workspaces_access_rights ,
12+ )
13+ from simcore_postgres_database .utils_repos import (
14+ pass_or_acquire_connection ,
15+ )
16+ from sqlalchemy .ext .asyncio import AsyncConnection
617
18+ from ..db .plugin import get_asyncpg_engine
719from .exceptions import ProjectNotFoundError
820
921
1022async def get_project_owner (engine : Engine , project_uuid : ProjectID ) -> UserID :
1123 async with engine .acquire () as connection :
12- stmt = sqlalchemy .select (projects .c .prj_owner ).where (
24+ stmt = sa .select (projects .c .prj_owner ).where (
1325 projects .c .uuid == f"{ project_uuid } "
1426 )
1527
@@ -18,3 +30,94 @@ async def get_project_owner(engine: Engine, project_uuid: ProjectID) -> UserID:
1830 raise ProjectNotFoundError (project_uuid = project_uuid )
1931 assert isinstance (owner_id , int )
2032 return owner_id
33+
34+
35+ def _split_private_and_shared_projects (
36+ projects_uuids_with_workspace_id : list [tuple [ProjectID , WorkspaceID | None ]],
37+ ) -> tuple [list [ProjectID ], dict [WorkspaceID , list [ProjectID ]]]:
38+ """Splits project tuples into private project IDs and a mapping of workspace_id to project IDs."""
39+ private_project_ids = []
40+ workspace_to_project_ids : dict [WorkspaceID , list [ProjectID ]] = {}
41+ for pid , wid in projects_uuids_with_workspace_id :
42+ if wid is None :
43+ private_project_ids .append (pid )
44+ else :
45+ workspace_to_project_ids .setdefault (wid , []).append (pid )
46+ return private_project_ids , workspace_to_project_ids
47+
48+
49+ async def batch_get_project_access_rights (
50+ app : web .Application ,
51+ connection : AsyncConnection | None = None ,
52+ * ,
53+ projects_uuids_with_workspace_id : list [tuple [ProjectID , WorkspaceID | None ]],
54+ ) -> dict [ProjectIDStr , dict [GroupID , dict [str , bool ]]]:
55+ private_project_ids , workspace_to_project_ids = _split_private_and_shared_projects (
56+ projects_uuids_with_workspace_id
57+ )
58+ shared_workspace_ids = set (workspace_to_project_ids .keys ())
59+ results = {}
60+
61+ async with pass_or_acquire_connection (get_asyncpg_engine (app ), connection ) as conn :
62+ # Query private workspace projects
63+ if private_project_ids :
64+ private_query = (
65+ sa .select (
66+ project_to_groups .c .project_uuid ,
67+ sa .func .jsonb_object_agg (
68+ project_to_groups .c .gid ,
69+ sa .func .jsonb_build_object (
70+ "read" ,
71+ project_to_groups .c .read ,
72+ "write" ,
73+ project_to_groups .c .write ,
74+ "delete" ,
75+ project_to_groups .c .delete ,
76+ ),
77+ ).label ("access_rights" ),
78+ )
79+ .where (
80+ project_to_groups .c .project_uuid .in_ (
81+ [f"{ uuid } " for uuid in private_project_ids ]
82+ )
83+ )
84+ .group_by (project_to_groups .c .project_uuid )
85+ )
86+ private_result = await conn .stream (private_query )
87+ async for row in private_result :
88+ results [row .project_uuid ] = row .access_rights
89+
90+ # Query shared workspace projects by workspace_id
91+ if shared_workspace_ids :
92+ shared_query = (
93+ sa .select (
94+ workspaces_access_rights .c .workspace_id ,
95+ sa .func .jsonb_object_agg (
96+ workspaces_access_rights .c .gid ,
97+ sa .func .jsonb_build_object (
98+ "read" ,
99+ workspaces_access_rights .c .read ,
100+ "write" ,
101+ workspaces_access_rights .c .write ,
102+ "delete" ,
103+ workspaces_access_rights .c .delete ,
104+ ),
105+ ).label ("access_rights" ),
106+ )
107+ .where (
108+ workspaces_access_rights .c .workspace_id .in_ (shared_workspace_ids )
109+ )
110+ .group_by (workspaces_access_rights .c .workspace_id )
111+ )
112+ shared_result = await conn .stream (shared_query )
113+ workspace_access_rights_map = {}
114+ async for row in shared_result :
115+ workspace_access_rights_map [row .workspace_id ] = row .access_rights
116+ # Assign access rights to each project in the workspace
117+ for wid , project_ids in workspace_to_project_ids .items ():
118+ access_rights = workspace_access_rights_map .get (wid )
119+ if access_rights is not None :
120+ for pid in project_ids :
121+ results [f"{ pid } " ] = access_rights
122+
123+ return results
0 commit comments