1- from numpy import diff
21import sqlalchemy
3- from aiopg .sa .engine import Engine
4- from models_library .projects import ProjectID
5- from models_library .users import UserID
6- from simcore_postgres_database .models .projects import projects
7- import logging
8- from collections .abc import Callable
9- from datetime import datetime
10- from typing import cast
11-
122import sqlalchemy as sa
133from aiohttp import web
14- from common_library .exclude import UnSet , is_set
15- from models_library .basic_types import IDStr
4+ from aiopg .sa .engine import Engine
165from models_library .groups import GroupID
176from models_library .projects import ProjectID
18- from models_library .rest_ordering import OrderBy , OrderDirection
19- from models_library .rest_pagination import MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE
7+ from models_library .users import UserID
208from models_library .workspaces import WorkspaceID
21- from pydantic import NonNegativeInt , PositiveInt
22- from simcore_postgres_database .models .projects import projects
239from simcore_postgres_database .models .project_to_groups import project_to_groups
24- from simcore_postgres_database .models .users import users
10+ from simcore_postgres_database .models .projects import projects
11+ from simcore_postgres_database .models .workspace_access_rights import (
12+ workspace_access_rights ,
13+ )
2514from simcore_postgres_database .utils_repos import (
26- get_columns_from_db_model ,
2715 pass_or_acquire_connection ,
28- transaction_context ,
2916)
30- from sqlalchemy import sql
3117from sqlalchemy .ext .asyncio import AsyncConnection
3218
3319from ..db .plugin import get_asyncpg_engine
3420from .exceptions import ProjectNotFoundError
35- from .models import ProjectDBGet
36- from .exceptions import ProjectNotFoundError
3721
3822
3923async def get_project_owner (engine : Engine , project_uuid : ProjectID ) -> UserID :
@@ -53,56 +37,75 @@ async def batch_get_project_access_rights(
5337 app : web .Application ,
5438 connection : AsyncConnection | None = None ,
5539 * ,
56- projects_uuids : list [ProjectID ],
40+ projects_uuids_with_workspace_id : list [
41+ tuple [ProjectID , WorkspaceID | None ]
42+ ], # list of tuples (project_uuid, workspace_id)
5743) -> dict [ProjectID , dict [GroupID , dict [str , bool ]]]:
44+ # Split into private and shared workspace project IDs
45+ private_project_ids = [
46+ pid for pid , wid in projects_uuids_with_workspace_id if wid is None
47+ ]
48+ shared_project_ids = [
49+ pid for pid , wid in projects_uuids_with_workspace_id if wid is not None
50+ ]
5851
59- # NOTE: MD: TODO: differentiate between private/shared workspaces
60- # based on that use either project_to_groups or workspace_access_rights
52+ results = {}
6153
62- private_workspace_access_rights_query = (
63- sa .select (
64- project_to_groups .c .project_uuid ,
65- sa .func .jsonb_object_agg (
66- project_to_groups .c .gid ,
67- sa .func .jsonb_build_object (
68- "read" ,
69- project_to_groups .c .read ,
70- "write" ,
71- project_to_groups .c .write ,
72- "delete" ,
73- project_to_groups .c .delete ,
74- ),
75- ).label ("access_rights" ),
76- )
77- .where (
78- (projects .c .uuid .in_ ([f"{ uuid } " for uuid in projects_uuids ])) # <-- this needs to be prefiltered based on workspace
79- & (project_to_groups .c .read )
80- )
81- .group_by (project_to_groups .c .project_uuid )
82- )
54+ async with pass_or_acquire_connection (get_asyncpg_engine (app ), connection ) as conn :
55+ # Query private workspace projects
56+ if private_project_ids :
57+ private_query = (
58+ sa .select (
59+ project_to_groups .c .project_uuid ,
60+ sa .func .jsonb_object_agg (
61+ project_to_groups .c .gid ,
62+ sa .func .jsonb_build_object (
63+ "read" ,
64+ project_to_groups .c .read ,
65+ "write" ,
66+ project_to_groups .c .write ,
67+ "delete" ,
68+ project_to_groups .c .delete ,
69+ ),
70+ ).label ("access_rights" ),
71+ )
72+ .where (
73+ project_to_groups .c .project_uuid .in_ (
74+ [f"{ uuid } " for uuid in private_project_ids ]
75+ )
76+ )
77+ .group_by (project_to_groups .c .project_uuid )
78+ )
79+ private_result = await conn .stream (private_query )
80+ async for row in private_result :
81+ results [row .project_uuid ] = row .access_rights
8382
84- shared_workspace_access_rights_query = (
85- sa .select (
86- workspace_access_rights .c .project_uuid ,
87- sa .func .jsonb_object_agg (
88- project_to_groups .c .gid ,
89- sa .func .jsonb_build_object (
90- "read" ,
91- workspace_access_rights .c .read ,
92- "write" ,
93- workspace_access_rights .c .write ,
94- "delete" ,
95- workspace_access_rights .c .delete ,
96- ),
97- ).label ("access_rights" ),
98- )
99- .where (
100- (projects .c .uuid .in_ ([f"{ uuid } " for uuid in projects_uuids ])) # <-- this needs to be prefiltered based on workspace
101- & (workspace_access_rights .c .read )
102- )
103- .group_by (workspace_access_rights .c .project_uuid )
104- )
83+ # Query shared workspace projects
84+ if shared_project_ids :
85+ shared_query = (
86+ sa .select (
87+ workspace_access_rights .c .project_uuid ,
88+ sa .func .jsonb_object_agg (
89+ workspace_access_rights .c .gid ,
90+ sa .func .jsonb_build_object (
91+ "read" ,
92+ workspace_access_rights .c .read ,
93+ "write" ,
94+ workspace_access_rights .c .write ,
95+ "delete" ,
96+ workspace_access_rights .c .delete ,
97+ ),
98+ ).label ("access_rights" ),
99+ )
100+ .where (
101+ workspace_access_rights .c .project_uuid .in_ (
102+ [f"{ uuid } " for uuid in shared_project_ids ]
103+ )
104+ )
105+ .group_by (workspace_access_rights .c .project_uuid )
106+ )
107+ shared_result = await conn .stream (shared_query )
108+ async for row in shared_result :
109+ results [row .project_uuid ] = row .access_rights
105110
106- async with pass_or_acquire_connection (get_asyncpg_engine (app ), connection ) as conn :
107- result = await conn .stream (access_rights_query )
108- return {row .project_uuid : row .access_rights async for row in result }
111+ return results
0 commit comments