Skip to content

Commit 81d1bd9

Browse files
authored
Add permission function service layer methods 🎨 (#8211)
1 parent 64d6099 commit 81d1bd9

File tree

12 files changed

+271
-38
lines changed

12 files changed

+271
-38
lines changed

β€Žservices/api-server/src/simcore_service_api_server/api/routes/function_job_collections_routes.pyβ€Ž

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import asyncio
21
from typing import Annotated, Final
32

43
from fastapi import APIRouter, Depends, status
@@ -14,19 +13,18 @@
1413
)
1514
from models_library.products import ProductName
1615
from models_library.users import UserID
16+
from servicelib.utils import limited_gather
1717
from simcore_service_api_server._service_function_jobs import FunctionJobService
18-
from simcore_service_api_server.api.dependencies.functions import (
19-
get_stored_job_status, # Import UserID
20-
)
21-
from simcore_service_api_server.api.dependencies.functions import (
22-
get_function_from_functionjobid,
23-
)
2418

2519
from ...models.pagination import Page, PaginationParams
2620
from ...models.schemas.errors import ErrorGet
2721
from ...services_http.director_v2 import DirectorV2Api
2822
from ...services_rpc.wb_api_server import WbApiRpcClient
2923
from ..dependencies.authentication import get_current_user_id, get_product_name
24+
from ..dependencies.functions import (
25+
get_function_from_functionjobid,
26+
get_stored_job_status,
27+
)
3028
from ..dependencies.models_schemas_function_filters import (
3129
get_function_job_collections_filters,
3230
)
@@ -269,7 +267,7 @@ async def function_job_collection_status(
269267
product_name=product_name,
270268
)
271269

272-
job_statuses = await asyncio.gather(
270+
job_statuses = await limited_gather(
273271
*[
274272
function_job_status(
275273
function_job=await get_function_job(
@@ -286,9 +284,9 @@ async def function_job_collection_status(
286284
),
287285
stored_job_status=await get_stored_job_status(
288286
function_job_id=function_job_id,
287+
wb_api_rpc=wb_api_rpc,
289288
user_id=user_id,
290289
product_name=product_name,
291-
wb_api_rpc=wb_api_rpc,
292290
),
293291
wb_api_rpc=wb_api_rpc,
294292
director2_api=director2_api,

β€Žservices/api-server/src/simcore_service_api_server/api/routes/function_jobs_routes.pyβ€Ž

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,12 @@
2121
from models_library.projects_state import RunningState
2222
from models_library.users import UserID
2323
from servicelib.fastapi.dependencies import get_app
24-
from simcore_service_api_server._service_function_jobs import FunctionJobService
25-
from simcore_service_api_server.api.dependencies.functions import (
26-
get_function_from_functionjob,
27-
get_function_job_dependency,
28-
get_stored_job_outputs,
29-
get_stored_job_status,
30-
)
31-
from simcore_service_api_server.api.dependencies.models_schemas_function_filters import (
32-
get_function_jobs_filters,
33-
)
3424
from simcore_service_api_server.models.schemas.functions_filters import (
3525
FunctionJobsListFilters,
3626
)
3727
from sqlalchemy.ext.asyncio import AsyncEngine
3828

29+
from ..._service_function_jobs import FunctionJobService
3930
from ..._service_jobs import JobService
4031
from ...models.pagination import Page, PaginationParams
4132
from ...models.schemas.errors import ErrorGet
@@ -45,6 +36,13 @@
4536
from ...services_rpc.wb_api_server import WbApiRpcClient
4637
from ..dependencies.authentication import get_current_user_id, get_product_name
4738
from ..dependencies.database import get_db_asyncpg_engine
39+
from ..dependencies.functions import (
40+
get_function_from_functionjob,
41+
get_function_job_dependency,
42+
get_stored_job_outputs,
43+
get_stored_job_status,
44+
)
45+
from ..dependencies.models_schemas_function_filters import get_function_jobs_filters
4846
from ..dependencies.services import (
4947
get_api_client,
5048
get_function_job_service,

β€Žservices/api-server/src/simcore_service_api_server/api/routes/functions_routes.pyβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@
3636
from models_library.projects_state import RunningState
3737
from models_library.users import UserID
3838
from servicelib.fastapi.dependencies import get_reverse_url_mapper
39-
from simcore_service_api_server._service_function_jobs import FunctionJobService
40-
from simcore_service_api_server._service_functions import FunctionService
41-
from simcore_service_api_server._service_jobs import JobService
42-
from simcore_service_api_server.api.dependencies.functions import get_stored_job_status
4339

40+
from ..._service_function_jobs import FunctionJobService
41+
from ..._service_functions import FunctionService
42+
from ..._service_jobs import JobService
4443
from ..._service_solvers import SolverService
4544
from ...models.pagination import Page, PaginationParams
4645
from ...models.schemas.errors import ErrorGet
@@ -49,6 +48,7 @@
4948
from ...services_http.webserver import AuthSession
5049
from ...services_rpc.wb_api_server import WbApiRpcClient
5150
from ..dependencies.authentication import get_current_user_id, get_product_name
51+
from ..dependencies.functions import get_stored_job_status
5252
from ..dependencies.services import (
5353
get_api_client,
5454
get_function_job_service,

β€Žservices/api-server/src/simcore_service_api_server/api/routes/studies_jobs.pyβ€Ž

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@
6060
)
6161
from .solvers_jobs import JOBS_STATUS_CODES
6262

63-
# pylint: disable=too-many-arguments
64-
65-
6663
_logger = logging.getLogger(__name__)
6764

6865

β€Žservices/web/server/src/simcore_service_webserver/functions/_functions_repository.pyβ€Ž

Lines changed: 116 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,10 @@ async def create_function( # noqa: PLR0913
154154
user_primary_group_id = await users_service.get_user_primary_group_id(
155155
app, user_id=user_id
156156
)
157-
await set_group_permissions(
157+
await _internal_set_group_permissions(
158158
app,
159159
connection=transaction,
160-
group_id=user_primary_group_id,
160+
permission_group_id=user_primary_group_id,
161161
product_name=product_name,
162162
object_type="function",
163163
object_ids=[registered_function.uuid],
@@ -214,10 +214,10 @@ async def create_function_job( # noqa: PLR0913
214214
user_primary_group_id = await users_service.get_user_primary_group_id(
215215
app, user_id=user_id
216216
)
217-
await set_group_permissions(
217+
await _internal_set_group_permissions(
218218
app,
219219
connection=transaction,
220-
group_id=user_primary_group_id,
220+
permission_group_id=user_primary_group_id,
221221
product_name=product_name,
222222
object_type="function_job",
223223
object_ids=[registered_function_job.uuid],
@@ -301,10 +301,10 @@ async def create_function_job_collection(
301301
user_primary_group_id = await users_service.get_user_primary_group_id(
302302
app, user_id=user_id
303303
)
304-
await set_group_permissions(
304+
await _internal_set_group_permissions(
305305
app,
306306
connection=transaction,
307-
group_id=user_primary_group_id,
307+
permission_group_id=user_primary_group_id,
308308
product_name=product_name,
309309
object_type="function_job_collection",
310310
object_ids=[function_job_collection_db.uuid],
@@ -1006,7 +1006,113 @@ async def set_group_permissions(
10061006
app: web.Application,
10071007
connection: AsyncConnection | None = None,
10081008
*,
1009-
group_id: GroupID,
1009+
user_id: UserID,
1010+
permission_group_id: GroupID,
1011+
product_name: ProductName,
1012+
object_type: Literal["function", "function_job", "function_job_collection"],
1013+
object_ids: list[UUID],
1014+
read: bool | None = None,
1015+
write: bool | None = None,
1016+
execute: bool | None = None,
1017+
) -> None:
1018+
async with pass_or_acquire_connection(get_asyncpg_engine(app), connection) as conn:
1019+
for object_id in object_ids:
1020+
await check_user_permissions(
1021+
app,
1022+
connection=conn,
1023+
user_id=user_id,
1024+
product_name=product_name,
1025+
object_id=object_id,
1026+
object_type=object_type,
1027+
permissions=["write"],
1028+
)
1029+
1030+
await _internal_set_group_permissions(
1031+
app,
1032+
connection=connection,
1033+
permission_group_id=permission_group_id,
1034+
product_name=product_name,
1035+
object_type=object_type,
1036+
object_ids=object_ids,
1037+
read=read,
1038+
write=write,
1039+
execute=execute,
1040+
)
1041+
1042+
1043+
async def remove_group_permissions(
1044+
app: web.Application,
1045+
connection: AsyncConnection | None = None,
1046+
*,
1047+
user_id: UserID,
1048+
permission_group_id: GroupID,
1049+
product_name: ProductName,
1050+
object_type: Literal["function", "function_job", "function_job_collection"],
1051+
object_ids: list[UUID],
1052+
) -> None:
1053+
async with pass_or_acquire_connection(get_asyncpg_engine(app), connection) as conn:
1054+
for object_id in object_ids:
1055+
await check_user_permissions(
1056+
app,
1057+
connection=conn,
1058+
user_id=user_id,
1059+
product_name=product_name,
1060+
object_id=object_id,
1061+
object_type=object_type,
1062+
permissions=["write"],
1063+
)
1064+
1065+
await _internal_remove_group_permissions(
1066+
app,
1067+
connection=connection,
1068+
permission_group_id=permission_group_id,
1069+
product_name=product_name,
1070+
object_type=object_type,
1071+
object_ids=object_ids,
1072+
)
1073+
1074+
1075+
async def _internal_remove_group_permissions(
1076+
app: web.Application,
1077+
connection: AsyncConnection | None = None,
1078+
*,
1079+
permission_group_id: GroupID,
1080+
product_name: ProductName,
1081+
object_type: Literal["function", "function_job", "function_job_collection"],
1082+
object_ids: list[UUID],
1083+
) -> None:
1084+
access_rights_table = None
1085+
field_name = None
1086+
1087+
if object_type == "function":
1088+
access_rights_table = functions_access_rights_table
1089+
field_name = "function_uuid"
1090+
elif object_type == "function_job":
1091+
access_rights_table = function_jobs_access_rights_table
1092+
field_name = "function_job_uuid"
1093+
elif object_type == "function_job_collection":
1094+
access_rights_table = function_job_collections_access_rights_table
1095+
field_name = "function_job_collection_uuid"
1096+
1097+
assert access_rights_table is not None # nosec
1098+
assert field_name is not None # nosec
1099+
1100+
async with transaction_context(get_asyncpg_engine(app), connection) as transaction:
1101+
for object_id in object_ids:
1102+
await transaction.execute(
1103+
access_rights_table.delete().where(
1104+
getattr(access_rights_table.c, field_name) == object_id,
1105+
access_rights_table.c.group_id == permission_group_id,
1106+
access_rights_table.c.product_name == product_name,
1107+
)
1108+
)
1109+
1110+
1111+
async def _internal_set_group_permissions(
1112+
app: web.Application,
1113+
connection: AsyncConnection | None = None,
1114+
*,
1115+
permission_group_id: GroupID,
10101116
product_name: ProductName,
10111117
object_type: Literal["function", "function_job", "function_job_collection"],
10121118
object_ids: list[UUID],
@@ -1035,7 +1141,7 @@ async def set_group_permissions(
10351141
result = await transaction.execute(
10361142
access_rights_table.select().where(
10371143
getattr(access_rights_table.c, field_name) == object_id,
1038-
access_rights_table.c.group_id == group_id,
1144+
access_rights_table.c.group_id == permission_group_id,
10391145
)
10401146
)
10411147
row = result.one_or_none()
@@ -1045,7 +1151,7 @@ async def set_group_permissions(
10451151
await transaction.execute(
10461152
access_rights_table.insert().values(
10471153
**{field_name: object_id},
1048-
group_id=group_id,
1154+
group_id=permission_group_id,
10491155
product_name=product_name,
10501156
read=read if read is not None else False,
10511157
write=write if write is not None else False,
@@ -1064,7 +1170,7 @@ async def set_group_permissions(
10641170
access_rights_table.update()
10651171
.where(
10661172
getattr(access_rights_table.c, field_name) == object_id,
1067-
access_rights_table.c.group_id == group_id,
1173+
access_rights_table.c.group_id == permission_group_id,
10681174
)
10691175
.values(**update_values)
10701176
)

β€Žservices/web/server/src/simcore_service_webserver/functions/_functions_service.pyβ€Ž

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
FunctionClass,
55
FunctionClassSpecificData,
66
FunctionDB,
7+
FunctionGroupAccessRights,
78
FunctionID,
89
FunctionInputs,
910
FunctionInputSchema,
@@ -34,6 +35,7 @@
3435
UnsupportedFunctionClassError,
3536
UnsupportedFunctionJobClassError,
3637
)
38+
from models_library.groups import GroupID
3739
from models_library.products import ProductName
3840
from models_library.rest_pagination import PageMetaInfoLimitOffset
3941
from models_library.users import UserID
@@ -438,6 +440,45 @@ async def get_function_user_permissions(
438440
)
439441

440442

443+
async def set_function_group_permissions(
444+
app: web.Application,
445+
*,
446+
user_id: UserID,
447+
product_name: ProductName,
448+
function_id: FunctionID,
449+
permissions: FunctionGroupAccessRights,
450+
) -> None:
451+
await _functions_repository.set_group_permissions(
452+
app=app,
453+
user_id=user_id,
454+
product_name=product_name,
455+
object_ids=[function_id],
456+
object_type="function",
457+
permission_group_id=permissions.group_id,
458+
read=permissions.read,
459+
write=permissions.write,
460+
execute=permissions.execute,
461+
)
462+
463+
464+
async def remove_function_group_permissions(
465+
app: web.Application,
466+
*,
467+
user_id: UserID,
468+
product_name: ProductName,
469+
function_id: FunctionID,
470+
permission_group_id: GroupID,
471+
) -> None:
472+
await _functions_repository.remove_group_permissions(
473+
app=app,
474+
user_id=user_id,
475+
product_name=product_name,
476+
object_ids=[function_id],
477+
object_type="function",
478+
permission_group_id=permission_group_id,
479+
)
480+
481+
441482
async def get_function_job_status(
442483
app: web.Application,
443484
*,

0 commit comments

Comments
Β (0)