diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a214ca09..2ce714e457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * API: * Major endpoint changes: * Add trailing slash to _all_ endpoints' paths (\#1003). - * Add new monitoring endpoints restricted to superusers at `/monitoring` (\#947). + * Add new monitoring endpoints restricted to superusers at `/monitoring` (\#947, \#1009). * Add new `GET` endpoints `api/v1/job/` and `api/v1/project/{project_id}/workflow/{workflow_id}/job/` (\#969, \#1003). * Add new `GET` endpoints `api/v1/dataset/` and `api/v1/workflow/` (\#988, \#1003). * Add new `GET` endpoint `api/v1/project/{project_id}/dataset/` (\#993). diff --git a/fractal_server/app/routes/monitoring.py b/fractal_server/app/routes/monitoring.py index 07c39c7290..b03ce02385 100644 --- a/fractal_server/app/routes/monitoring.py +++ b/fractal_server/app/routes/monitoring.py @@ -16,12 +16,12 @@ from ..models import JobStatusType from ..models import Project from ..models import Workflow +from ..models.security import UserOAuth as User from ..schemas import ApplyWorkflowRead from ..schemas import DatasetRead from ..schemas import ProjectRead from ..schemas import WorkflowRead from ..security import current_active_superuser -from ..security import User router_monitoring = APIRouter() @@ -60,6 +60,7 @@ async def monitor_project( @router_monitoring.get("/workflow/", response_model=list[WorkflowRead]) async def monitor_workflow( id: Optional[int] = None, + user_id: Optional[int] = None, project_id: Optional[int] = None, name_contains: Optional[str] = None, user: User = Depends(current_active_superuser), @@ -76,6 +77,10 @@ async def monitor_workflow( """ stm = select(Workflow) + if user_id is not None: + stm = stm.join(Project).where( + Project.user_list.any(User.id == user_id) + ) if id is not None: stm = stm.where(Workflow.id == id) if project_id is not None: @@ -96,6 +101,7 @@ async def monitor_workflow( @router_monitoring.get("/dataset/", response_model=list[DatasetRead]) async def monitor_dataset( id: Optional[int] = None, + user_id: Optional[int] = None, project_id: Optional[int] = None, name_contains: Optional[str] = None, type: Optional[str] = None, @@ -114,6 +120,10 @@ async def monitor_dataset( """ stm = select(Dataset) + if user_id is not None: + stm = stm.join(Project).where( + Project.user_list.any(User.id == user_id) + ) if id is not None: stm = stm.where(Dataset.id == id) if project_id is not None: @@ -136,6 +146,7 @@ async def monitor_dataset( @router_monitoring.get("/job/", response_model=list[ApplyWorkflowRead]) async def monitor_job( id: Optional[int] = None, + user_id: Optional[int] = None, project_id: Optional[int] = None, input_dataset_id: Optional[int] = None, output_dataset_id: Optional[int] = None, @@ -173,6 +184,10 @@ async def monitor_job( if id is not None: stm = stm.where(ApplyWorkflow.id == id) + if user_id is not None: + stm = stm.join(Project).where( + Project.user_list.any(User.id == user_id) + ) if project_id is not None: stm = stm.where(ApplyWorkflow.project_id == project_id) if input_dataset_id is not None: diff --git a/tests/test_monitoring.py b/tests/test_monitoring.py index 7cb3a72734..fa2cd53cdd 100644 --- a/tests/test_monitoring.py +++ b/tests/test_monitoring.py @@ -92,14 +92,24 @@ async def test_monitor_workflow( async with MockCurrentUser( persist=True, user_kwargs={"is_superuser": True} - ): + ) as superuser: + project3 = await project_factory(superuser) + await workflow_factory(project_id=project3.id, name="super") + # get all workflows res = await client.get(f"{PREFIX}/workflow/") assert res.status_code == 200 + assert len(res.json()) == 4 + + # get workflows by user_id + res = await client.get(f"{PREFIX}/workflow/?user_id={user.id}") + assert res.status_code == 200 assert len(res.json()) == 3 # get workflows by id - res = await client.get(f"{PREFIX}/workflow/?id={workflow1a.id}") + res = await client.get( + f"{PREFIX}/workflow/?user_id={user.id}&id={workflow1a.id}" + ) assert res.status_code == 200 assert len(res.json()) == 1 assert res.json()[0]["name"] == workflow1a.name @@ -169,10 +179,22 @@ async def test_monitor_dataset( async with MockCurrentUser( persist=True, user_kwargs={"is_superuser": True} - ): + ) as superuser: + super_project = await project_factory(superuser) + await dataset_factory( + project_id=super_project.id, + name="super-d", + type="zarr", + ) + # get all datasets res = await client.get(f"{PREFIX}/dataset/") assert res.status_code == 200 + assert len(res.json()) == 4 + + # get datasets by user_id + res = await client.get(f"{PREFIX}/dataset/?user_id={user.id}") + assert res.status_code == 200 assert len(res.json()) == 3 # get datasets by id @@ -206,7 +228,9 @@ async def test_monitor_dataset( assert len(res.json()) == 0 # get datasets by type - res = await client.get(f"{PREFIX}/dataset/?type=zarr") + res = await client.get( + f"{PREFIX}/dataset/?type=zarr&user_id={user.id}" + ) assert res.status_code == 200 assert len(res.json()) == 2 res = await client.get(f"{PREFIX}/dataset/?type=image") @@ -270,6 +294,14 @@ async def test_monitor_job( assert res.status_code == 200 assert len(res.json()) == 2 + # get jobs by user_id + res = await client.get(f"{PREFIX}/job/?user_id={user.id}") + assert res.status_code == 200 + assert len(res.json()) == 2 + res = await client.get(f"{PREFIX}/job/?user_id={user.id + 1}") + assert res.status_code == 200 + assert len(res.json()) == 0 + # get jobs by id res = await client.get(f"{PREFIX}/job/?id={job1.id}") assert res.status_code == 200