Skip to content

Commit 143120f

Browse files
authored
Add a check_write_permissions option to update function job/out 🐛 (#8325)
1 parent 9ad66db commit 143120f

File tree

9 files changed

+229
-47
lines changed

9 files changed

+229
-47
lines changed

packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/webserver/functions/functions_rpc_interface.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from typing import Literal
23

34
from models_library.api_schemas_webserver import WEBSERVER_RPC_NAMESPACE
45
from models_library.api_schemas_webserver.functions import (
@@ -18,6 +19,7 @@
1819
)
1920
from models_library.functions import (
2021
FunctionClass,
22+
FunctionGroupAccessRights,
2123
FunctionJobStatus,
2224
FunctionOutputs,
2325
FunctionUserAccessRights,
@@ -418,6 +420,7 @@ async def update_function_job_status(
418420
product_name: ProductName,
419421
function_job_id: FunctionJobID,
420422
job_status: FunctionJobStatus,
423+
check_write_permissions: bool = True,
421424
) -> FunctionJobStatus:
422425
result = await rabbitmq_rpc_client.request(
423426
WEBSERVER_RPC_NAMESPACE,
@@ -426,6 +429,7 @@ async def update_function_job_status(
426429
job_status=job_status,
427430
user_id=user_id,
428431
product_name=product_name,
432+
check_write_permissions=check_write_permissions,
429433
)
430434
return TypeAdapter(FunctionJobStatus).validate_python(result)
431435

@@ -438,6 +442,7 @@ async def update_function_job_outputs(
438442
product_name: ProductName,
439443
function_job_id: FunctionJobID,
440444
outputs: FunctionOutputs,
445+
check_write_permissions: bool = True,
441446
) -> FunctionOutputs:
442447
result = await rabbitmq_rpc_client.request(
443448
WEBSERVER_RPC_NAMESPACE,
@@ -446,6 +451,7 @@ async def update_function_job_outputs(
446451
outputs=outputs,
447452
user_id=user_id,
448453
product_name=product_name,
454+
check_write_permissions=check_write_permissions,
449455
)
450456
return TypeAdapter(FunctionOutputs).validate_python(result)
451457

@@ -578,3 +584,37 @@ async def get_functions_user_api_access_rights(
578584
product_name=product_name,
579585
)
580586
return TypeAdapter(FunctionUserApiAccessRights).validate_python(result)
587+
588+
589+
@log_decorator(_logger, level=logging.DEBUG)
590+
async def set_group_permissions(
591+
rabbitmq_rpc_client: RabbitMQRPCClient,
592+
*,
593+
user_id: UserID,
594+
product_name: ProductName,
595+
object_type: Literal["function", "function_job", "function_job_collection"],
596+
object_ids: list[FunctionID | FunctionJobID | FunctionJobCollectionID],
597+
permission_group_id: int,
598+
read: bool | None = None,
599+
write: bool | None = None,
600+
execute: bool | None = None,
601+
) -> list[
602+
tuple[
603+
FunctionID | FunctionJobID | FunctionJobCollectionID, FunctionGroupAccessRights
604+
]
605+
]:
606+
result = await rabbitmq_rpc_client.request(
607+
WEBSERVER_RPC_NAMESPACE,
608+
TypeAdapter(RPCMethodName).validate_python("set_group_permissions"),
609+
user_id=user_id,
610+
product_name=product_name,
611+
object_type=object_type,
612+
object_ids=object_ids,
613+
permission_group_id=permission_group_id,
614+
read=read,
615+
write=write,
616+
execute=execute,
617+
)
618+
return TypeAdapter(
619+
list[tuple[FunctionID | FunctionJobID, FunctionGroupAccessRights]]
620+
).validate_python(result)

services/api-server/src/simcore_service_api_server/_service_function_jobs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ async def inspect_function_job(
203203
user_id=self.user_id,
204204
product_name=self.product_name,
205205
job_status=new_job_status,
206+
check_write_permissions=False,
206207
)
207208

208209
async def create_function_job_inputs( # pylint: disable=no-self-use
@@ -529,4 +530,5 @@ async def function_job_outputs(
529530
user_id=user_id,
530531
product_name=product_name,
531532
outputs=new_outputs,
533+
check_write_permissions=False,
532534
)

services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,13 +587,15 @@ async def update_function_job_status(
587587
user_id: UserID,
588588
product_name: ProductName,
589589
job_status: FunctionJobStatus,
590+
check_write_permissions: bool = True,
590591
) -> FunctionJobStatus:
591592
return await functions_rpc_interface.update_function_job_status(
592593
self._client,
593594
function_job_id=function_job_id,
594595
user_id=user_id,
595596
product_name=product_name,
596597
job_status=job_status,
598+
check_write_permissions=check_write_permissions,
597599
)
598600

599601
async def update_function_job_outputs(
@@ -603,13 +605,15 @@ async def update_function_job_outputs(
603605
user_id: UserID,
604606
product_name: ProductName,
605607
outputs: FunctionOutputs,
608+
check_write_permissions: bool = True,
606609
) -> FunctionOutputs:
607610
return await functions_rpc_interface.update_function_job_outputs(
608611
self._client,
609612
function_job_id=function_job_id,
610613
user_id=user_id,
611614
product_name=product_name,
612615
outputs=outputs,
616+
check_write_permissions=check_write_permissions,
613617
)
614618

615619
async def find_cached_function_jobs(

services/web/server/src/simcore_service_webserver/functions/_controller/_functions_rest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ async def register_function(request: web.Request) -> web.Response:
169169
@login_required
170170
@permission_required("function.read")
171171
@handle_rest_requests_exceptions
172-
async def list_functions(request: web.Request) -> web.Response:
172+
async def list_functions(request: web.Request) -> web.Response: # noqa: C901
173173
query_params: FunctionsListQueryParams = parse_request_query_parameters_as(
174174
FunctionsListQueryParams, request
175175
)

services/web/server/src/simcore_service_webserver/functions/_controller/_functions_rpc.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
from typing import Literal
2+
13
from aiohttp import web
24
from models_library.api_schemas_webserver import WEBSERVER_RPC_NAMESPACE
35
from models_library.functions import (
46
Function,
57
FunctionAccessRights,
68
FunctionClass,
9+
FunctionGroupAccessRights,
710
FunctionID,
811
FunctionInputs,
912
FunctionInputSchema,
@@ -43,6 +46,7 @@
4346
UnsupportedFunctionClassError,
4447
UnsupportedFunctionJobClassError,
4548
)
49+
from models_library.groups import GroupID
4650
from models_library.products import ProductName
4751
from models_library.rest_ordering import OrderBy
4852
from models_library.rest_pagination import PageMetaInfoLimitOffset
@@ -495,39 +499,55 @@ async def get_function_job_outputs(
495499
)
496500

497501

498-
@router.expose(reraise_if_error_type=(FunctionJobIDNotFoundError,))
502+
@router.expose(
503+
reraise_if_error_type=(
504+
FunctionJobIDNotFoundError,
505+
FunctionJobWriteAccessDeniedError,
506+
FunctionJobReadAccessDeniedError,
507+
)
508+
)
499509
async def update_function_job_status(
500510
app: web.Application,
501511
*,
502512
user_id: UserID,
503513
product_name: ProductName,
504514
function_job_id: FunctionJobID,
505515
job_status: FunctionJobStatus,
516+
check_write_permissions: bool = True,
506517
) -> FunctionJobStatus:
507518
return await _functions_service.update_function_job_status(
508519
app=app,
509520
user_id=user_id,
510521
product_name=product_name,
511522
function_job_id=function_job_id,
512523
job_status=job_status,
524+
check_write_permissions=check_write_permissions,
513525
)
514526

515527

516-
@router.expose(reraise_if_error_type=(FunctionJobIDNotFoundError,))
528+
@router.expose(
529+
reraise_if_error_type=(
530+
FunctionJobIDNotFoundError,
531+
FunctionJobWriteAccessDeniedError,
532+
FunctionJobReadAccessDeniedError,
533+
)
534+
)
517535
async def update_function_job_outputs(
518536
app: web.Application,
519537
*,
520538
user_id: UserID,
521539
product_name: ProductName,
522540
function_job_id: FunctionJobID,
523541
outputs: FunctionOutputs,
542+
check_write_permissions: bool = True,
524543
) -> FunctionOutputs:
525544
return await _functions_service.update_function_job_outputs(
526545
app=app,
527546
user_id=user_id,
528547
product_name=product_name,
529548
function_job_id=function_job_id,
530549
outputs=outputs,
550+
check_write_permissions=check_write_permissions,
531551
)
532552

533553

@@ -586,3 +606,33 @@ async def get_functions_user_api_access_rights(
586606
async def register_rpc_routes_on_startup(app: web.Application):
587607
rpc_server = get_rabbitmq_rpc_server(app)
588608
await rpc_server.register_router(router, WEBSERVER_RPC_NAMESPACE, app)
609+
610+
611+
@router.expose(reraise_if_error_type=())
612+
async def set_group_permissions(
613+
app: web.Application,
614+
*,
615+
user_id: UserID,
616+
permission_group_id: GroupID,
617+
product_name: ProductName,
618+
object_type: Literal["function", "function_job", "function_job_collection"],
619+
object_ids: list[FunctionID | FunctionJobID | FunctionJobCollectionID],
620+
read: bool | None = None,
621+
write: bool | None = None,
622+
execute: bool | None = None,
623+
) -> list[
624+
tuple[
625+
FunctionID | FunctionJobID | FunctionJobCollectionID, FunctionGroupAccessRights
626+
]
627+
]:
628+
return await _functions_service.set_group_permissions(
629+
app=app,
630+
user_id=user_id,
631+
permission_group_id=permission_group_id,
632+
product_name=product_name,
633+
object_type=object_type,
634+
object_ids=object_ids,
635+
read=read,
636+
write=write,
637+
execute=execute,
638+
)

services/web/server/src/simcore_service_webserver/functions/_functions_repository.py

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -663,22 +663,10 @@ async def update_function_job_status(
663663
app: web.Application,
664664
connection: AsyncConnection | None = None,
665665
*,
666-
user_id: UserID,
667-
product_name: ProductName,
668666
function_job_id: FunctionJobID,
669667
job_status: FunctionJobStatus,
670668
) -> FunctionJobStatus:
671669
async with transaction_context(get_asyncpg_engine(app), connection) as transaction:
672-
await check_user_permissions(
673-
app,
674-
connection=transaction,
675-
user_id=user_id,
676-
product_name=product_name,
677-
object_type="function_job",
678-
object_id=function_job_id,
679-
permissions=["write"],
680-
)
681-
682670
result = await transaction.execute(
683671
function_jobs_table.update()
684672
.where(function_jobs_table.c.uuid == function_job_id)
@@ -697,22 +685,10 @@ async def update_function_job_outputs(
697685
app: web.Application,
698686
connection: AsyncConnection | None = None,
699687
*,
700-
user_id: UserID,
701-
product_name: ProductName,
702688
function_job_id: FunctionJobID,
703689
outputs: FunctionOutputs,
704690
) -> FunctionOutputs:
705691
async with transaction_context(get_asyncpg_engine(app), connection) as transaction:
706-
await check_user_permissions(
707-
app,
708-
connection=transaction,
709-
user_id=user_id,
710-
product_name=product_name,
711-
object_type="function_job",
712-
object_id=function_job_id,
713-
permissions=["write"],
714-
)
715-
716692
result = await transaction.execute(
717693
function_jobs_table.update()
718694
.where(function_jobs_table.c.uuid == function_job_id)
@@ -1141,11 +1117,15 @@ async def set_group_permissions(
11411117
permission_group_id: GroupID,
11421118
product_name: ProductName,
11431119
object_type: Literal["function", "function_job", "function_job_collection"],
1144-
object_ids: list[UUID],
1120+
object_ids: list[FunctionID | FunctionJobID | FunctionJobCollectionID],
11451121
read: bool | None = None,
11461122
write: bool | None = None,
11471123
execute: bool | None = None,
1148-
) -> list[tuple[UUID, FunctionGroupAccessRights]]:
1124+
) -> list[
1125+
tuple[
1126+
FunctionID | FunctionJobID | FunctionJobCollectionID, FunctionGroupAccessRights
1127+
]
1128+
]:
11491129
async with pass_or_acquire_connection(get_asyncpg_engine(app), connection) as conn:
11501130
for object_id in object_ids:
11511131
await check_user_permissions(
@@ -1245,8 +1225,13 @@ async def _internal_get_group_permissions(
12451225
*,
12461226
product_name: ProductName,
12471227
object_type: Literal["function", "function_job", "function_job_collection"],
1248-
object_ids: list[UUID],
1249-
) -> list[tuple[UUID, list[FunctionGroupAccessRights]]]:
1228+
object_ids: list[FunctionID | FunctionJobID | FunctionJobCollectionID],
1229+
) -> list[
1230+
tuple[
1231+
FunctionID | FunctionJobID | FunctionJobCollectionID,
1232+
list[FunctionGroupAccessRights],
1233+
]
1234+
]:
12501235
access_rights_table = None
12511236
field_name = None
12521237
if object_type == "function":

0 commit comments

Comments
 (0)