Skip to content

Commit 32365a0

Browse files
committed
Add a check_write_permissions option to update function job/out
1 parent a58201f commit 32365a0

File tree

9 files changed

+209
-19
lines changed

9 files changed

+209
-19
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: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -667,16 +667,20 @@ async def update_function_job_status(
667667
product_name: ProductName,
668668
function_job_id: FunctionJobID,
669669
job_status: FunctionJobStatus,
670+
check_write_permissions: bool = True,
670671
) -> FunctionJobStatus:
671672
async with transaction_context(get_asyncpg_engine(app), connection) as transaction:
673+
checked_permissions: list[Literal["read", "write", "execute"]] = ["read"]
674+
if check_write_permissions:
675+
checked_permissions.append("write")
672676
await check_user_permissions(
673677
app,
674678
connection=transaction,
675679
user_id=user_id,
676680
product_name=product_name,
677681
object_type="function_job",
678682
object_id=function_job_id,
679-
permissions=["write"],
683+
permissions=checked_permissions,
680684
)
681685

682686
result = await transaction.execute(
@@ -701,16 +705,20 @@ async def update_function_job_outputs(
701705
product_name: ProductName,
702706
function_job_id: FunctionJobID,
703707
outputs: FunctionOutputs,
708+
check_write_permissions: bool = True,
704709
) -> FunctionOutputs:
705710
async with transaction_context(get_asyncpg_engine(app), connection) as transaction:
711+
checked_permissions: list[Literal["read", "write", "execute"]] = ["read"]
712+
if check_write_permissions:
713+
checked_permissions.append("write")
706714
await check_user_permissions(
707715
app,
708716
connection=transaction,
709717
user_id=user_id,
710718
product_name=product_name,
711719
object_type="function_job",
712720
object_id=function_job_id,
713-
permissions=["write"],
721+
permissions=checked_permissions,
714722
)
715723

716724
result = await transaction.execute(
@@ -1141,11 +1149,15 @@ async def set_group_permissions(
11411149
permission_group_id: GroupID,
11421150
product_name: ProductName,
11431151
object_type: Literal["function", "function_job", "function_job_collection"],
1144-
object_ids: list[UUID],
1152+
object_ids: list[FunctionID | FunctionJobID | FunctionJobCollectionID],
11451153
read: bool | None = None,
11461154
write: bool | None = None,
11471155
execute: bool | None = None,
1148-
) -> list[tuple[UUID, FunctionGroupAccessRights]]:
1156+
) -> list[
1157+
tuple[
1158+
FunctionID | FunctionJobID | FunctionJobCollectionID, FunctionGroupAccessRights
1159+
]
1160+
]:
11491161
async with pass_or_acquire_connection(get_asyncpg_engine(app), connection) as conn:
11501162
for object_id in object_ids:
11511163
await check_user_permissions(

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Literal
2+
13
from aiohttp import web
24
from models_library.basic_types import IDStr
35
from models_library.functions import (
@@ -607,6 +609,35 @@ async def remove_function_group_permissions(
607609
)
608610

609611

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_repository.set_group_permissions(
629+
app=app,
630+
user_id=user_id,
631+
product_name=product_name,
632+
object_type=object_type,
633+
object_ids=object_ids,
634+
permission_group_id=permission_group_id,
635+
read=read,
636+
write=write,
637+
execute=execute,
638+
)
639+
640+
610641
async def get_function_job_status(
611642
app: web.Application,
612643
*,
@@ -644,13 +675,15 @@ async def update_function_job_outputs(
644675
product_name: ProductName,
645676
function_job_id: FunctionJobID,
646677
outputs: FunctionOutputs,
678+
check_write_permissions: bool = True,
647679
) -> FunctionOutputs:
648680
return await _functions_repository.update_function_job_outputs(
649681
app=app,
650682
user_id=user_id,
651683
product_name=product_name,
652684
function_job_id=function_job_id,
653685
outputs=outputs,
686+
check_write_permissions=check_write_permissions,
654687
)
655688

656689

@@ -661,13 +694,15 @@ async def update_function_job_status(
661694
product_name: ProductName,
662695
function_job_id: FunctionJobID,
663696
job_status: FunctionJobStatus,
697+
check_write_permissions: bool = True,
664698
) -> FunctionJobStatus:
665699
return await _functions_repository.update_function_job_status(
666700
app=app,
667701
user_id=user_id,
668702
product_name=product_name,
669703
function_job_id=function_job_id,
670704
job_status=job_status,
705+
check_write_permissions=check_write_permissions,
671706
)
672707

673708

0 commit comments

Comments
 (0)