fractal-server 2.17.1a1__py3-none-any.whl → 2.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fractal_server/__init__.py +1 -1
- fractal_server/__main__.py +21 -19
- fractal_server/app/db/__init__.py +3 -3
- fractal_server/app/models/__init__.py +1 -0
- fractal_server/app/models/linkuserproject.py +43 -1
- fractal_server/app/models/security.py +28 -8
- fractal_server/app/models/v2/__init__.py +3 -1
- fractal_server/app/models/v2/accounting.py +9 -1
- fractal_server/app/models/v2/dataset.py +5 -1
- fractal_server/app/models/v2/history.py +15 -1
- fractal_server/app/models/v2/job.py +17 -2
- fractal_server/app/models/v2/profile.py +29 -0
- fractal_server/app/models/v2/project.py +4 -10
- fractal_server/app/models/v2/resource.py +17 -0
- fractal_server/app/models/v2/task_group.py +4 -3
- fractal_server/app/models/v2/workflow.py +2 -1
- fractal_server/app/routes/admin/v2/__init__.py +12 -13
- fractal_server/app/routes/admin/v2/accounting.py +3 -3
- fractal_server/app/routes/admin/v2/job.py +35 -24
- fractal_server/app/routes/admin/v2/profile.py +3 -2
- fractal_server/app/routes/admin/v2/resource.py +5 -5
- fractal_server/app/routes/admin/v2/sharing.py +103 -0
- fractal_server/app/routes/admin/v2/task.py +37 -26
- fractal_server/app/routes/admin/v2/task_group.py +94 -17
- fractal_server/app/routes/admin/v2/task_group_lifecycle.py +21 -22
- fractal_server/app/routes/api/__init__.py +1 -9
- fractal_server/app/routes/api/v2/__init__.py +49 -50
- fractal_server/app/routes/api/v2/_aux_functions.py +132 -124
- fractal_server/app/routes/api/v2/_aux_functions_history.py +51 -23
- fractal_server/app/routes/api/v2/_aux_functions_sharing.py +97 -0
- fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +6 -8
- fractal_server/app/routes/api/v2/_aux_functions_tasks.py +7 -9
- fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +1 -2
- fractal_server/app/routes/api/v2/dataset.py +95 -102
- fractal_server/app/routes/api/v2/history.py +59 -33
- fractal_server/app/routes/api/v2/images.py +24 -9
- fractal_server/app/routes/api/v2/job.py +52 -33
- fractal_server/app/routes/api/v2/pre_submission_checks.py +16 -8
- fractal_server/app/routes/api/v2/project.py +65 -37
- fractal_server/app/routes/api/v2/sharing.py +311 -0
- fractal_server/app/routes/api/v2/status_legacy.py +31 -41
- fractal_server/app/routes/api/v2/submit.py +82 -78
- fractal_server/app/routes/api/v2/task.py +19 -20
- fractal_server/app/routes/api/v2/task_collection.py +41 -43
- fractal_server/app/routes/api/v2/task_collection_custom.py +19 -20
- fractal_server/app/routes/api/v2/task_collection_pixi.py +10 -11
- fractal_server/app/routes/api/v2/task_group.py +25 -24
- fractal_server/app/routes/api/v2/task_group_lifecycle.py +32 -32
- fractal_server/app/routes/api/v2/task_version_update.py +23 -19
- fractal_server/app/routes/api/v2/workflow.py +50 -55
- fractal_server/app/routes/api/v2/workflow_import.py +37 -37
- fractal_server/app/routes/api/v2/workflowtask.py +32 -26
- fractal_server/app/routes/auth/__init__.py +1 -3
- fractal_server/app/routes/auth/_aux_auth.py +101 -2
- fractal_server/app/routes/auth/current_user.py +2 -66
- fractal_server/app/routes/auth/group.py +8 -35
- fractal_server/app/routes/auth/login.py +1 -0
- fractal_server/app/routes/auth/oauth.py +4 -3
- fractal_server/app/routes/auth/register.py +4 -2
- fractal_server/app/routes/auth/router.py +2 -0
- fractal_server/app/routes/auth/users.py +19 -10
- fractal_server/app/routes/auth/viewer_paths.py +43 -0
- fractal_server/app/routes/aux/_job.py +1 -1
- fractal_server/app/routes/aux/_runner.py +2 -2
- fractal_server/app/routes/pagination.py +1 -1
- fractal_server/app/schemas/user.py +29 -12
- fractal_server/app/schemas/user_group.py +0 -15
- fractal_server/app/schemas/v2/__init__.py +55 -48
- fractal_server/app/schemas/v2/accounting.py +11 -0
- fractal_server/app/schemas/v2/dataset.py +57 -11
- fractal_server/app/schemas/v2/dumps.py +10 -9
- fractal_server/app/schemas/v2/job.py +11 -11
- fractal_server/app/schemas/v2/manifest.py +4 -3
- fractal_server/app/schemas/v2/profile.py +53 -2
- fractal_server/app/schemas/v2/project.py +3 -3
- fractal_server/app/schemas/v2/resource.py +121 -16
- fractal_server/app/schemas/v2/sharing.py +99 -0
- fractal_server/app/schemas/v2/status_legacy.py +3 -3
- fractal_server/app/schemas/v2/task.py +6 -7
- fractal_server/app/schemas/v2/task_collection.py +5 -5
- fractal_server/app/schemas/v2/task_group.py +16 -16
- fractal_server/app/schemas/v2/workflow.py +16 -16
- fractal_server/app/schemas/v2/workflowtask.py +16 -15
- fractal_server/app/security/__init__.py +5 -8
- fractal_server/app/security/signup_email.py +4 -5
- fractal_server/app/shutdown.py +6 -6
- fractal_server/config/__init__.py +0 -6
- fractal_server/config/_data.py +0 -68
- fractal_server/config/_database.py +19 -20
- fractal_server/config/_email.py +30 -38
- fractal_server/config/_main.py +38 -52
- fractal_server/config/_oauth.py +17 -21
- fractal_server/data_migrations/2_18_0.py +30 -0
- fractal_server/exceptions.py +4 -0
- fractal_server/images/models.py +4 -5
- fractal_server/images/status_tools.py +4 -2
- fractal_server/logger.py +1 -1
- fractal_server/main.py +75 -13
- fractal_server/migrations/versions/034a469ec2eb_task_groups.py +4 -8
- fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +1 -1
- fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +1 -0
- fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +1 -1
- fractal_server/migrations/versions/1a83a5260664_rename.py +1 -1
- fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +1 -0
- fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +1 -1
- fractal_server/migrations/versions/40d6d6511b20_add_index_to_history_models.py +47 -0
- fractal_server/migrations/versions/45fbb391d7af_make_resource_id_fk_non_nullable.py +1 -1
- fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +1 -0
- fractal_server/migrations/versions/49d0856e9569_drop_table.py +2 -3
- fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +1 -1
- fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +1 -1
- fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +2 -1
- fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +7 -19
- fractal_server/migrations/versions/5bf02391cfef_v2.py +4 -10
- fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +1 -0
- fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +1 -1
- fractal_server/migrations/versions/7673fe18c05d_remove_project_dir_server_default.py +1 -1
- fractal_server/migrations/versions/7910eed4cf97_user_project_dirs_and_usergroup_viewer_.py +60 -0
- fractal_server/migrations/versions/791ce783d3d8_add_indices.py +1 -1
- fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +1 -0
- fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +1 -0
- fractal_server/migrations/versions/88270f589c9b_add_prevent_new_submissions.py +39 -0
- fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +2 -4
- fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +1 -1
- fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +1 -0
- fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +1 -1
- fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +1 -1
- fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +1 -1
- fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +2 -4
- fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +1 -1
- fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +1 -1
- fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +1 -1
- fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +1 -1
- fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +1 -0
- fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +1 -0
- fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +1 -1
- fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +1 -0
- fractal_server/migrations/versions/bc0e8b3327a7_project_sharing.py +72 -0
- fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +1 -1
- fractal_server/migrations/versions/caba9fb1ea5e_drop_useroauth_user_settings_id.py +1 -1
- fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +4 -9
- fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +1 -0
- fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +1 -1
- fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +1 -0
- fractal_server/migrations/versions/e0e717ae2f26_delete_linkuserproject_ondelete_project.py +50 -0
- fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +1 -0
- fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +1 -1
- fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +1 -0
- fractal_server/migrations/versions/f0702066b007_one_submitted_job_per_dataset.py +40 -0
- fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +1 -1
- fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +1 -0
- fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +4 -9
- fractal_server/runner/config/_local.py +8 -5
- fractal_server/runner/config/_slurm.py +39 -33
- fractal_server/runner/config/slurm_mem_to_MB.py +0 -1
- fractal_server/runner/executors/base_runner.py +29 -4
- fractal_server/runner/executors/local/get_local_config.py +1 -0
- fractal_server/runner/executors/local/runner.py +14 -13
- fractal_server/runner/executors/slurm_common/_batching.py +9 -20
- fractal_server/runner/executors/slurm_common/base_slurm_runner.py +53 -27
- fractal_server/runner/executors/slurm_common/get_slurm_config.py +14 -7
- fractal_server/runner/executors/slurm_common/remote.py +3 -1
- fractal_server/runner/executors/slurm_common/slurm_config.py +2 -0
- fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +1 -3
- fractal_server/runner/executors/slurm_ssh/runner.py +16 -11
- fractal_server/runner/executors/slurm_ssh/tar_commands.py +1 -0
- fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +1 -0
- fractal_server/runner/executors/slurm_sudo/runner.py +16 -11
- fractal_server/runner/task_files.py +9 -3
- fractal_server/runner/v2/_local.py +12 -6
- fractal_server/runner/v2/_slurm_ssh.py +14 -7
- fractal_server/runner/v2/_slurm_sudo.py +14 -7
- fractal_server/runner/v2/db_tools.py +0 -1
- fractal_server/runner/v2/deduplicate_list.py +2 -1
- fractal_server/runner/v2/runner.py +44 -28
- fractal_server/runner/v2/runner_functions.py +22 -28
- fractal_server/runner/v2/submit_workflow.py +29 -15
- fractal_server/ssh/_fabric.py +6 -13
- fractal_server/string_tools.py +0 -1
- fractal_server/syringe.py +1 -1
- fractal_server/tasks/config/_pixi.py +1 -1
- fractal_server/tasks/config/_python.py +16 -9
- fractal_server/tasks/utils.py +0 -1
- fractal_server/tasks/v2/local/_utils.py +3 -3
- fractal_server/tasks/v2/local/collect.py +15 -18
- fractal_server/tasks/v2/local/collect_pixi.py +14 -16
- fractal_server/tasks/v2/local/deactivate.py +14 -15
- fractal_server/tasks/v2/local/deactivate_pixi.py +7 -7
- fractal_server/tasks/v2/local/delete.py +6 -8
- fractal_server/tasks/v2/local/reactivate.py +12 -12
- fractal_server/tasks/v2/local/reactivate_pixi.py +12 -12
- fractal_server/tasks/v2/ssh/_utils.py +3 -3
- fractal_server/tasks/v2/ssh/collect.py +19 -24
- fractal_server/tasks/v2/ssh/collect_pixi.py +22 -24
- fractal_server/tasks/v2/ssh/deactivate.py +17 -15
- fractal_server/tasks/v2/ssh/deactivate_pixi.py +8 -7
- fractal_server/tasks/v2/ssh/delete.py +12 -10
- fractal_server/tasks/v2/ssh/reactivate.py +16 -16
- fractal_server/tasks/v2/ssh/reactivate_pixi.py +13 -14
- fractal_server/tasks/v2/templates/1_create_venv.sh +2 -0
- fractal_server/tasks/v2/templates/2_pip_install.sh +2 -0
- fractal_server/tasks/v2/templates/3_pip_freeze.sh +2 -0
- fractal_server/tasks/v2/templates/4_pip_show.sh +2 -0
- fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +3 -1
- fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +2 -0
- fractal_server/tasks/v2/templates/pixi_1_extract.sh +2 -0
- fractal_server/tasks/v2/templates/pixi_2_install.sh +2 -0
- fractal_server/tasks/v2/templates/pixi_3_post_install.sh +2 -0
- fractal_server/tasks/v2/utils_background.py +10 -10
- fractal_server/tasks/v2/utils_database.py +5 -5
- fractal_server/tasks/v2/utils_package_names.py +1 -2
- fractal_server/tasks/v2/utils_pixi.py +1 -3
- fractal_server/types/__init__.py +98 -1
- fractal_server/types/validators/__init__.py +3 -0
- fractal_server/types/validators/_common_validators.py +33 -3
- fractal_server/types/validators/_workflow_task_arguments_validators.py +1 -2
- fractal_server/utils.py +1 -0
- fractal_server/zip_tools.py +34 -0
- {fractal_server-2.17.1a1.dist-info → fractal_server-2.18.0.dist-info}/METADATA +3 -2
- fractal_server-2.18.0.dist-info/RECORD +275 -0
- fractal_server/app/routes/admin/v2/project.py +0 -41
- fractal_server-2.17.1a1.dist-info/RECORD +0 -264
- {fractal_server-2.17.1a1.dist-info → fractal_server-2.18.0.dist-info}/WHEEL +0 -0
- {fractal_server-2.17.1a1.dist-info → fractal_server-2.18.0.dist-info}/entry_points.txt +0 -0
- {fractal_server-2.17.1a1.dist-info → fractal_server-2.18.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,40 +6,43 @@ from fastapi.responses import JSONResponse
|
|
|
6
6
|
from sqlmodel import func
|
|
7
7
|
from sqlmodel import select
|
|
8
8
|
|
|
9
|
-
from ._aux_functions import _get_dataset_check_owner
|
|
10
|
-
from ._aux_functions import _get_submitted_job_or_none
|
|
11
|
-
from ._aux_functions import _get_workflow_check_owner
|
|
12
|
-
from ._aux_functions_history import _verify_workflow_and_dataset_access
|
|
13
|
-
from ._aux_functions_history import get_history_run_or_404
|
|
14
|
-
from ._aux_functions_history import get_history_unit_or_404
|
|
15
|
-
from ._aux_functions_history import get_wftask_check_owner
|
|
16
|
-
from ._aux_functions_history import read_log_file
|
|
17
|
-
from .images import ImagePage
|
|
18
|
-
from .images import ImageQuery
|
|
19
9
|
from fractal_server.app.db import AsyncSession
|
|
20
10
|
from fractal_server.app.db import get_async_db
|
|
21
11
|
from fractal_server.app.models import UserOAuth
|
|
22
12
|
from fractal_server.app.models.v2 import HistoryImageCache
|
|
23
13
|
from fractal_server.app.models.v2 import HistoryRun
|
|
24
14
|
from fractal_server.app.models.v2 import HistoryUnit
|
|
15
|
+
from fractal_server.app.models.v2 import JobV2
|
|
25
16
|
from fractal_server.app.models.v2 import TaskV2
|
|
26
17
|
from fractal_server.app.routes.auth import current_user_act_ver_prof
|
|
27
|
-
from fractal_server.app.routes.pagination import get_pagination_params
|
|
28
18
|
from fractal_server.app.routes.pagination import PaginationRequest
|
|
29
19
|
from fractal_server.app.routes.pagination import PaginationResponse
|
|
20
|
+
from fractal_server.app.routes.pagination import get_pagination_params
|
|
30
21
|
from fractal_server.app.schemas.v2 import HistoryRunRead
|
|
31
22
|
from fractal_server.app.schemas.v2 import HistoryRunReadAggregated
|
|
32
23
|
from fractal_server.app.schemas.v2 import HistoryUnitRead
|
|
33
24
|
from fractal_server.app.schemas.v2 import HistoryUnitStatus
|
|
34
25
|
from fractal_server.app.schemas.v2 import HistoryUnitStatusWithUnset
|
|
35
26
|
from fractal_server.app.schemas.v2 import ImageLogsRequest
|
|
36
|
-
from fractal_server.
|
|
27
|
+
from fractal_server.app.schemas.v2.sharing import ProjectPermissions
|
|
37
28
|
from fractal_server.images.status_tools import IMAGE_STATUS_KEY
|
|
29
|
+
from fractal_server.images.status_tools import enrich_images_unsorted_async
|
|
38
30
|
from fractal_server.images.tools import aggregate_attributes
|
|
39
31
|
from fractal_server.images.tools import aggregate_types
|
|
40
32
|
from fractal_server.images.tools import filter_image_list
|
|
41
33
|
from fractal_server.logger import set_logger
|
|
42
34
|
|
|
35
|
+
from ._aux_functions import _get_dataset_check_access
|
|
36
|
+
from ._aux_functions import _get_submitted_jobs_statement
|
|
37
|
+
from ._aux_functions import _get_workflow_check_access
|
|
38
|
+
from ._aux_functions_history import _verify_workflow_and_dataset_access
|
|
39
|
+
from ._aux_functions_history import get_history_run_or_404
|
|
40
|
+
from ._aux_functions_history import get_history_unit_or_404
|
|
41
|
+
from ._aux_functions_history import get_wftask_check_access
|
|
42
|
+
from ._aux_functions_history import read_log_file
|
|
43
|
+
from .images import ImagePage
|
|
44
|
+
from .images import ImageQuery
|
|
45
|
+
|
|
43
46
|
|
|
44
47
|
def check_historyrun_related_to_dataset_and_wftask(
|
|
45
48
|
history_run: HistoryRun,
|
|
@@ -72,24 +75,28 @@ async def get_workflow_tasks_statuses(
|
|
|
72
75
|
db: AsyncSession = Depends(get_async_db),
|
|
73
76
|
) -> JSONResponse:
|
|
74
77
|
# Access control
|
|
75
|
-
workflow = await
|
|
78
|
+
workflow = await _get_workflow_check_access(
|
|
76
79
|
project_id=project_id,
|
|
77
80
|
workflow_id=workflow_id,
|
|
78
81
|
user_id=user.id,
|
|
82
|
+
required_permissions=ProjectPermissions.READ,
|
|
79
83
|
db=db,
|
|
80
84
|
)
|
|
81
|
-
await
|
|
85
|
+
await _get_dataset_check_access(
|
|
82
86
|
project_id=project_id,
|
|
83
87
|
dataset_id=dataset_id,
|
|
84
88
|
user_id=user.id,
|
|
89
|
+
required_permissions=ProjectPermissions.READ,
|
|
85
90
|
db=db,
|
|
86
91
|
)
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
dataset_id
|
|
91
|
-
workflow_id
|
|
93
|
+
res = await db.execute(
|
|
94
|
+
_get_submitted_jobs_statement()
|
|
95
|
+
.where(JobV2.dataset_id == dataset_id)
|
|
96
|
+
.where(JobV2.workflow_id == workflow_id)
|
|
92
97
|
)
|
|
98
|
+
running_job = res.scalars().one_or_none()
|
|
99
|
+
|
|
93
100
|
if running_job is not None:
|
|
94
101
|
running_wftasks = workflow.task_list[
|
|
95
102
|
running_job.first_task_index : running_job.last_task_index + 1
|
|
@@ -135,19 +142,19 @@ async def get_workflow_tasks_statuses(
|
|
|
135
142
|
logger.debug(f"C1: {wftask.id=} not in {running_wftask_ids=}.")
|
|
136
143
|
response[wftask.id] = dict(status=latest_run.status)
|
|
137
144
|
|
|
138
|
-
response[wftask.id][
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
response[wftask.id]["num_available_images"] = (
|
|
146
|
+
latest_run.num_available_images
|
|
147
|
+
)
|
|
141
148
|
|
|
142
149
|
for target_status in HistoryUnitStatus:
|
|
143
150
|
stm = (
|
|
144
151
|
select(func.count(HistoryImageCache.zarr_url))
|
|
145
|
-
.join(
|
|
152
|
+
.join(
|
|
153
|
+
HistoryUnit,
|
|
154
|
+
HistoryImageCache.latest_history_unit_id == HistoryUnit.id,
|
|
155
|
+
)
|
|
146
156
|
.where(HistoryImageCache.dataset_id == dataset_id)
|
|
147
157
|
.where(HistoryImageCache.workflowtask_id == wftask.id)
|
|
148
|
-
.where(
|
|
149
|
-
HistoryImageCache.latest_history_unit_id == HistoryUnit.id
|
|
150
|
-
)
|
|
151
158
|
.where(HistoryUnit.status == target_status)
|
|
152
159
|
)
|
|
153
160
|
res = await db.execute(stm)
|
|
@@ -183,11 +190,12 @@ async def get_history_run_list(
|
|
|
183
190
|
db: AsyncSession = Depends(get_async_db),
|
|
184
191
|
) -> list[HistoryRunReadAggregated]:
|
|
185
192
|
# Access control
|
|
186
|
-
await
|
|
193
|
+
await get_wftask_check_access(
|
|
187
194
|
project_id=project_id,
|
|
188
195
|
dataset_id=dataset_id,
|
|
189
196
|
workflowtask_id=workflowtask_id,
|
|
190
197
|
user_id=user.id,
|
|
198
|
+
required_permissions=ProjectPermissions.READ,
|
|
191
199
|
db=db,
|
|
192
200
|
)
|
|
193
201
|
|
|
@@ -276,11 +284,12 @@ async def get_history_run_units(
|
|
|
276
284
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
|
277
285
|
) -> PaginationResponse[HistoryUnitRead]:
|
|
278
286
|
# Access control
|
|
279
|
-
await
|
|
287
|
+
await get_wftask_check_access(
|
|
280
288
|
project_id=project_id,
|
|
281
289
|
dataset_id=dataset_id,
|
|
282
290
|
workflowtask_id=workflowtask_id,
|
|
283
291
|
user_id=user.id,
|
|
292
|
+
required_permissions=ProjectPermissions.READ,
|
|
284
293
|
db=db,
|
|
285
294
|
)
|
|
286
295
|
|
|
@@ -335,11 +344,12 @@ async def get_history_images(
|
|
|
335
344
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
|
336
345
|
) -> ImagePage:
|
|
337
346
|
# Access control and object retrieval
|
|
338
|
-
wftask = await
|
|
347
|
+
wftask = await get_wftask_check_access(
|
|
339
348
|
project_id=project_id,
|
|
340
349
|
dataset_id=dataset_id,
|
|
341
350
|
workflowtask_id=workflowtask_id,
|
|
342
351
|
user_id=user.id,
|
|
352
|
+
required_permissions=ProjectPermissions.READ,
|
|
343
353
|
db=db,
|
|
344
354
|
)
|
|
345
355
|
res = await _verify_workflow_and_dataset_access(
|
|
@@ -347,6 +357,7 @@ async def get_history_images(
|
|
|
347
357
|
workflow_id=wftask.workflow_id,
|
|
348
358
|
dataset_id=dataset_id,
|
|
349
359
|
user_id=user.id,
|
|
360
|
+
required_permissions=ProjectPermissions.READ,
|
|
350
361
|
db=db,
|
|
351
362
|
)
|
|
352
363
|
dataset = res["dataset"]
|
|
@@ -416,11 +427,12 @@ async def get_image_log(
|
|
|
416
427
|
db: AsyncSession = Depends(get_async_db),
|
|
417
428
|
) -> JSONResponse:
|
|
418
429
|
# Access control
|
|
419
|
-
wftask = await
|
|
430
|
+
wftask = await get_wftask_check_access(
|
|
420
431
|
project_id=project_id,
|
|
421
432
|
dataset_id=request_data.dataset_id,
|
|
422
433
|
workflowtask_id=request_data.workflowtask_id,
|
|
423
434
|
user_id=user.id,
|
|
435
|
+
required_permissions=ProjectPermissions.READ,
|
|
424
436
|
db=db,
|
|
425
437
|
)
|
|
426
438
|
|
|
@@ -444,11 +456,20 @@ async def get_image_log(
|
|
|
444
456
|
db=db,
|
|
445
457
|
)
|
|
446
458
|
|
|
459
|
+
# Get job.working_dir
|
|
460
|
+
res = await db.execute(
|
|
461
|
+
select(JobV2.working_dir)
|
|
462
|
+
.join(HistoryRun, HistoryRun.job_id == JobV2.id)
|
|
463
|
+
.where(HistoryRun.id == history_unit.history_run_id)
|
|
464
|
+
)
|
|
465
|
+
job_working_dir = res.scalar_one_or_none()
|
|
466
|
+
|
|
447
467
|
# Get log or placeholder text
|
|
448
468
|
log = read_log_file(
|
|
449
469
|
logfile=history_unit.logfile,
|
|
450
|
-
|
|
470
|
+
task_name=wftask.task.name,
|
|
451
471
|
dataset_id=request_data.dataset_id,
|
|
472
|
+
job_working_dir=job_working_dir,
|
|
452
473
|
)
|
|
453
474
|
return JSONResponse(content=log)
|
|
454
475
|
|
|
@@ -464,11 +485,12 @@ async def get_history_unit_log(
|
|
|
464
485
|
db: AsyncSession = Depends(get_async_db),
|
|
465
486
|
) -> JSONResponse:
|
|
466
487
|
# Access control
|
|
467
|
-
wftask = await
|
|
488
|
+
wftask = await get_wftask_check_access(
|
|
468
489
|
project_id=project_id,
|
|
469
490
|
dataset_id=dataset_id,
|
|
470
491
|
workflowtask_id=workflowtask_id,
|
|
471
492
|
user_id=user.id,
|
|
493
|
+
required_permissions=ProjectPermissions.READ,
|
|
472
494
|
db=db,
|
|
473
495
|
)
|
|
474
496
|
|
|
@@ -495,11 +517,14 @@ async def get_history_unit_log(
|
|
|
495
517
|
workflowtask_id=workflowtask_id,
|
|
496
518
|
)
|
|
497
519
|
|
|
520
|
+
job = await db.get(JobV2, history_run.job_id)
|
|
521
|
+
|
|
498
522
|
# Get log or placeholder text
|
|
499
523
|
log = read_log_file(
|
|
500
524
|
logfile=history_unit.logfile,
|
|
501
|
-
|
|
525
|
+
task_name=wftask.task.name,
|
|
502
526
|
dataset_id=dataset_id,
|
|
527
|
+
job_working_dir=job.working_dir,
|
|
503
528
|
)
|
|
504
529
|
return JSONResponse(content=log)
|
|
505
530
|
|
|
@@ -516,10 +541,11 @@ async def get_dataset_history(
|
|
|
516
541
|
timestamp.
|
|
517
542
|
"""
|
|
518
543
|
# Access control
|
|
519
|
-
await
|
|
544
|
+
await _get_dataset_check_access(
|
|
520
545
|
project_id=project_id,
|
|
521
546
|
dataset_id=dataset_id,
|
|
522
547
|
user_id=user.id,
|
|
548
|
+
required_permissions=ProjectPermissions.READ,
|
|
523
549
|
db=db,
|
|
524
550
|
)
|
|
525
551
|
|
|
@@ -8,15 +8,15 @@ from pydantic import Field
|
|
|
8
8
|
from sqlalchemy.orm.attributes import flag_modified
|
|
9
9
|
from sqlmodel import delete
|
|
10
10
|
|
|
11
|
-
from ._aux_functions import _get_dataset_check_owner
|
|
12
11
|
from fractal_server.app.db import AsyncSession
|
|
13
12
|
from fractal_server.app.db import get_async_db
|
|
14
13
|
from fractal_server.app.models import HistoryImageCache
|
|
15
14
|
from fractal_server.app.models import UserOAuth
|
|
16
15
|
from fractal_server.app.routes.auth import current_user_act_ver_prof
|
|
17
|
-
from fractal_server.app.routes.pagination import get_pagination_params
|
|
18
16
|
from fractal_server.app.routes.pagination import PaginationRequest
|
|
19
17
|
from fractal_server.app.routes.pagination import PaginationResponse
|
|
18
|
+
from fractal_server.app.routes.pagination import get_pagination_params
|
|
19
|
+
from fractal_server.app.schemas.v2.sharing import ProjectPermissions
|
|
20
20
|
from fractal_server.images import SingleImage
|
|
21
21
|
from fractal_server.images import SingleImageUpdate
|
|
22
22
|
from fractal_server.images.tools import aggregate_attributes
|
|
@@ -27,6 +27,8 @@ from fractal_server.types import AttributeFilters
|
|
|
27
27
|
from fractal_server.types import ImageAttributeValue
|
|
28
28
|
from fractal_server.types import TypeFilters
|
|
29
29
|
|
|
30
|
+
from ._aux_functions import _get_dataset_check_access
|
|
31
|
+
|
|
30
32
|
router = APIRouter()
|
|
31
33
|
|
|
32
34
|
|
|
@@ -63,8 +65,12 @@ async def post_new_image(
|
|
|
63
65
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
64
66
|
db: AsyncSession = Depends(get_async_db),
|
|
65
67
|
) -> Response:
|
|
66
|
-
output = await
|
|
67
|
-
project_id=project_id,
|
|
68
|
+
output = await _get_dataset_check_access(
|
|
69
|
+
project_id=project_id,
|
|
70
|
+
dataset_id=dataset_id,
|
|
71
|
+
user_id=user.id,
|
|
72
|
+
required_permissions=ProjectPermissions.WRITE,
|
|
73
|
+
db=db,
|
|
68
74
|
)
|
|
69
75
|
dataset = output["dataset"]
|
|
70
76
|
|
|
@@ -118,8 +124,12 @@ async def query_dataset_images(
|
|
|
118
124
|
page = pagination.page
|
|
119
125
|
page_size = pagination.page_size
|
|
120
126
|
|
|
121
|
-
output = await
|
|
122
|
-
project_id=project_id,
|
|
127
|
+
output = await _get_dataset_check_access(
|
|
128
|
+
project_id=project_id,
|
|
129
|
+
dataset_id=dataset_id,
|
|
130
|
+
user_id=user.id,
|
|
131
|
+
required_permissions=ProjectPermissions.READ,
|
|
132
|
+
db=db,
|
|
123
133
|
)
|
|
124
134
|
dataset = output["dataset"]
|
|
125
135
|
images = dataset.images
|
|
@@ -186,8 +196,12 @@ async def delete_dataset_images(
|
|
|
186
196
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
187
197
|
db: AsyncSession = Depends(get_async_db),
|
|
188
198
|
) -> Response:
|
|
189
|
-
output = await
|
|
190
|
-
project_id=project_id,
|
|
199
|
+
output = await _get_dataset_check_access(
|
|
200
|
+
project_id=project_id,
|
|
201
|
+
dataset_id=dataset_id,
|
|
202
|
+
user_id=user.id,
|
|
203
|
+
required_permissions=ProjectPermissions.WRITE,
|
|
204
|
+
db=db,
|
|
191
205
|
)
|
|
192
206
|
dataset = output["dataset"]
|
|
193
207
|
|
|
@@ -230,10 +244,11 @@ async def patch_dataset_image(
|
|
|
230
244
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
231
245
|
db: AsyncSession = Depends(get_async_db),
|
|
232
246
|
):
|
|
233
|
-
output = await
|
|
247
|
+
output = await _get_dataset_check_access(
|
|
234
248
|
project_id=project_id,
|
|
235
249
|
dataset_id=dataset_id,
|
|
236
250
|
user_id=user.id,
|
|
251
|
+
required_permissions=ProjectPermissions.WRITE,
|
|
237
252
|
db=db,
|
|
238
253
|
)
|
|
239
254
|
db_dataset = output["dataset"]
|
|
@@ -10,21 +10,23 @@ from fastapi import status
|
|
|
10
10
|
from fastapi.responses import StreamingResponse
|
|
11
11
|
from sqlmodel import select
|
|
12
12
|
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from ....db import get_async_db
|
|
16
|
-
from ....models.v2 import JobV2
|
|
17
|
-
from ....models.v2 import ProjectV2
|
|
18
|
-
from ....schemas.v2 import JobReadV2
|
|
19
|
-
from ....schemas.v2 import JobStatusTypeV2
|
|
20
|
-
from ...aux._job import _write_shutdown_file
|
|
21
|
-
from ...aux._runner import _check_shutdown_is_supported
|
|
22
|
-
from ._aux_functions import _get_job_check_owner
|
|
23
|
-
from ._aux_functions import _get_project_check_owner
|
|
24
|
-
from ._aux_functions import _get_workflow_check_owner
|
|
13
|
+
from fractal_server.app.db import AsyncSession
|
|
14
|
+
from fractal_server.app.db import get_async_db
|
|
25
15
|
from fractal_server.app.models import UserOAuth
|
|
16
|
+
from fractal_server.app.models.v2 import JobV2
|
|
17
|
+
from fractal_server.app.models.v2 import LinkUserProjectV2
|
|
26
18
|
from fractal_server.app.routes.auth import current_user_act_ver_prof
|
|
19
|
+
from fractal_server.app.routes.aux._job import _write_shutdown_file
|
|
20
|
+
from fractal_server.app.routes.aux._runner import _check_shutdown_is_supported
|
|
21
|
+
from fractal_server.app.schemas.v2 import JobRead
|
|
22
|
+
from fractal_server.app.schemas.v2 import JobStatusType
|
|
23
|
+
from fractal_server.app.schemas.v2.sharing import ProjectPermissions
|
|
27
24
|
from fractal_server.runner.filenames import WORKFLOW_LOG_FILENAME
|
|
25
|
+
from fractal_server.zip_tools import _zip_folder_to_byte_stream_iterator
|
|
26
|
+
|
|
27
|
+
from ._aux_functions import _get_job_check_access
|
|
28
|
+
from ._aux_functions import _get_project_check_access
|
|
29
|
+
from ._aux_functions import _get_workflow_check_access
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
# https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
|
|
@@ -37,19 +39,22 @@ async def zip_folder_threaded(folder: str) -> Iterator[bytes]:
|
|
|
37
39
|
router = APIRouter()
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
@router.get("/job/", response_model=list[
|
|
42
|
+
@router.get("/job/", response_model=list[JobRead])
|
|
41
43
|
async def get_user_jobs(
|
|
42
44
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
43
45
|
log: bool = True,
|
|
44
46
|
db: AsyncSession = Depends(get_async_db),
|
|
45
|
-
) -> list[
|
|
47
|
+
) -> list[JobRead]:
|
|
46
48
|
"""
|
|
47
49
|
Returns all the jobs of the current user
|
|
48
50
|
"""
|
|
49
51
|
stm = (
|
|
50
52
|
select(JobV2)
|
|
51
|
-
.join(
|
|
52
|
-
|
|
53
|
+
.join(
|
|
54
|
+
LinkUserProjectV2, LinkUserProjectV2.project_id == JobV2.project_id
|
|
55
|
+
)
|
|
56
|
+
.where(LinkUserProjectV2.user_id == user.id)
|
|
57
|
+
.where(LinkUserProjectV2.is_owner.is_(True))
|
|
53
58
|
)
|
|
54
59
|
res = await db.execute(stm)
|
|
55
60
|
job_list = res.scalars().all()
|
|
@@ -63,19 +68,23 @@ async def get_user_jobs(
|
|
|
63
68
|
|
|
64
69
|
@router.get(
|
|
65
70
|
"/project/{project_id}/workflow/{workflow_id}/job/",
|
|
66
|
-
response_model=list[
|
|
71
|
+
response_model=list[JobRead],
|
|
67
72
|
)
|
|
68
73
|
async def get_workflow_jobs(
|
|
69
74
|
project_id: int,
|
|
70
75
|
workflow_id: int,
|
|
71
76
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
72
77
|
db: AsyncSession = Depends(get_async_db),
|
|
73
|
-
) -> list[
|
|
78
|
+
) -> list[JobRead] | None:
|
|
74
79
|
"""
|
|
75
80
|
Returns all the jobs related to a specific workflow
|
|
76
81
|
"""
|
|
77
|
-
await
|
|
78
|
-
project_id=project_id,
|
|
82
|
+
await _get_workflow_check_access(
|
|
83
|
+
project_id=project_id,
|
|
84
|
+
workflow_id=workflow_id,
|
|
85
|
+
user_id=user.id,
|
|
86
|
+
required_permissions=ProjectPermissions.READ,
|
|
87
|
+
db=db,
|
|
79
88
|
)
|
|
80
89
|
stm = select(JobV2).where(JobV2.workflow_id == workflow_id)
|
|
81
90
|
res = await db.execute(stm)
|
|
@@ -90,9 +99,13 @@ async def get_latest_job(
|
|
|
90
99
|
dataset_id: int,
|
|
91
100
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
92
101
|
db: AsyncSession = Depends(get_async_db),
|
|
93
|
-
) ->
|
|
94
|
-
await
|
|
95
|
-
project_id=project_id,
|
|
102
|
+
) -> JobRead:
|
|
103
|
+
await _get_workflow_check_access(
|
|
104
|
+
project_id=project_id,
|
|
105
|
+
workflow_id=workflow_id,
|
|
106
|
+
user_id=user.id,
|
|
107
|
+
required_permissions=ProjectPermissions.READ,
|
|
108
|
+
db=db,
|
|
96
109
|
)
|
|
97
110
|
stm = (
|
|
98
111
|
select(JobV2)
|
|
@@ -114,7 +127,7 @@ async def get_latest_job(
|
|
|
114
127
|
|
|
115
128
|
@router.get(
|
|
116
129
|
"/project/{project_id}/job/{job_id}/",
|
|
117
|
-
response_model=
|
|
130
|
+
response_model=JobRead,
|
|
118
131
|
)
|
|
119
132
|
async def read_job(
|
|
120
133
|
project_id: int,
|
|
@@ -122,21 +135,22 @@ async def read_job(
|
|
|
122
135
|
show_tmp_logs: bool = False,
|
|
123
136
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
124
137
|
db: AsyncSession = Depends(get_async_db),
|
|
125
|
-
) ->
|
|
138
|
+
) -> JobRead | None:
|
|
126
139
|
"""
|
|
127
140
|
Return info on an existing job
|
|
128
141
|
"""
|
|
129
142
|
|
|
130
|
-
output = await
|
|
143
|
+
output = await _get_job_check_access(
|
|
131
144
|
project_id=project_id,
|
|
132
145
|
job_id=job_id,
|
|
133
146
|
user_id=user.id,
|
|
147
|
+
required_permissions=ProjectPermissions.READ,
|
|
134
148
|
db=db,
|
|
135
149
|
)
|
|
136
150
|
job = output["job"]
|
|
137
151
|
await db.close()
|
|
138
152
|
|
|
139
|
-
if show_tmp_logs and (job.status ==
|
|
153
|
+
if show_tmp_logs and (job.status == JobStatusType.SUBMITTED):
|
|
140
154
|
try:
|
|
141
155
|
with open(f"{job.working_dir}/{WORKFLOW_LOG_FILENAME}") as f:
|
|
142
156
|
job.log = f.read()
|
|
@@ -159,10 +173,11 @@ async def download_job_logs(
|
|
|
159
173
|
"""
|
|
160
174
|
Download zipped job folder
|
|
161
175
|
"""
|
|
162
|
-
output = await
|
|
176
|
+
output = await _get_job_check_access(
|
|
163
177
|
project_id=project_id,
|
|
164
178
|
job_id=job_id,
|
|
165
179
|
user_id=user.id,
|
|
180
|
+
required_permissions=ProjectPermissions.READ,
|
|
166
181
|
db=db,
|
|
167
182
|
)
|
|
168
183
|
job = output["job"]
|
|
@@ -179,19 +194,22 @@ async def download_job_logs(
|
|
|
179
194
|
|
|
180
195
|
@router.get(
|
|
181
196
|
"/project/{project_id}/job/",
|
|
182
|
-
response_model=list[
|
|
197
|
+
response_model=list[JobRead],
|
|
183
198
|
)
|
|
184
199
|
async def get_job_list(
|
|
185
200
|
project_id: int,
|
|
186
201
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
187
202
|
log: bool = True,
|
|
188
203
|
db: AsyncSession = Depends(get_async_db),
|
|
189
|
-
) -> list[
|
|
204
|
+
) -> list[JobRead] | None:
|
|
190
205
|
"""
|
|
191
206
|
Get job list for given project
|
|
192
207
|
"""
|
|
193
|
-
project = await
|
|
194
|
-
project_id=project_id,
|
|
208
|
+
project = await _get_project_check_access(
|
|
209
|
+
project_id=project_id,
|
|
210
|
+
user_id=user.id,
|
|
211
|
+
required_permissions=ProjectPermissions.READ,
|
|
212
|
+
db=db,
|
|
195
213
|
)
|
|
196
214
|
|
|
197
215
|
stm = select(JobV2).where(JobV2.project_id == project.id)
|
|
@@ -222,10 +240,11 @@ async def stop_job(
|
|
|
222
240
|
_check_shutdown_is_supported()
|
|
223
241
|
|
|
224
242
|
# Get job from DB
|
|
225
|
-
output = await
|
|
243
|
+
output = await _get_job_check_access(
|
|
226
244
|
project_id=project_id,
|
|
227
245
|
job_id=job_id,
|
|
228
246
|
user_id=user.id,
|
|
247
|
+
required_permissions=ProjectPermissions.EXECUTE,
|
|
229
248
|
db=db,
|
|
230
249
|
)
|
|
231
250
|
job = output["job"]
|
|
@@ -5,21 +5,23 @@ from fastapi.responses import JSONResponse
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
from pydantic import Field
|
|
7
7
|
|
|
8
|
-
from ._aux_functions import _get_dataset_check_owner
|
|
9
|
-
from ._aux_functions import _get_workflow_task_check_owner
|
|
10
|
-
from .images import ImageQuery
|
|
11
8
|
from fractal_server.app.db import AsyncSession
|
|
12
9
|
from fractal_server.app.db import get_async_db
|
|
13
10
|
from fractal_server.app.models import UserOAuth
|
|
14
11
|
from fractal_server.app.routes.auth import current_user_act_ver_prof
|
|
15
12
|
from fractal_server.app.schemas.v2 import HistoryUnitStatus
|
|
16
13
|
from fractal_server.app.schemas.v2 import TaskType
|
|
17
|
-
from fractal_server.
|
|
14
|
+
from fractal_server.app.schemas.v2.sharing import ProjectPermissions
|
|
18
15
|
from fractal_server.images.status_tools import IMAGE_STATUS_KEY
|
|
16
|
+
from fractal_server.images.status_tools import enrich_images_unsorted_async
|
|
19
17
|
from fractal_server.images.tools import aggregate_types
|
|
20
18
|
from fractal_server.images.tools import filter_image_list
|
|
21
19
|
from fractal_server.types import AttributeFilters
|
|
22
20
|
|
|
21
|
+
from ._aux_functions import _get_dataset_check_access
|
|
22
|
+
from ._aux_functions import _get_workflow_task_check_access
|
|
23
|
+
from .images import ImageQuery
|
|
24
|
+
|
|
23
25
|
router = APIRouter()
|
|
24
26
|
|
|
25
27
|
|
|
@@ -36,8 +38,12 @@ async def verify_unique_types(
|
|
|
36
38
|
db: AsyncSession = Depends(get_async_db),
|
|
37
39
|
) -> list[str]:
|
|
38
40
|
# Get dataset
|
|
39
|
-
output = await
|
|
40
|
-
project_id=project_id,
|
|
41
|
+
output = await _get_dataset_check_access(
|
|
42
|
+
project_id=project_id,
|
|
43
|
+
dataset_id=dataset_id,
|
|
44
|
+
user_id=user.id,
|
|
45
|
+
required_permissions=ProjectPermissions.READ,
|
|
46
|
+
db=db,
|
|
41
47
|
)
|
|
42
48
|
dataset = output["dataset"]
|
|
43
49
|
|
|
@@ -96,11 +102,12 @@ async def check_non_processed_images(
|
|
|
96
102
|
user: UserOAuth = Depends(current_user_act_ver_prof),
|
|
97
103
|
db: AsyncSession = Depends(get_async_db),
|
|
98
104
|
) -> JSONResponse:
|
|
99
|
-
db_workflow_task, db_workflow = await
|
|
105
|
+
db_workflow_task, db_workflow = await _get_workflow_task_check_access(
|
|
100
106
|
project_id=project_id,
|
|
101
107
|
workflow_task_id=workflowtask_id,
|
|
102
108
|
workflow_id=workflow_id,
|
|
103
109
|
user_id=user.id,
|
|
110
|
+
required_permissions=ProjectPermissions.READ,
|
|
104
111
|
db=db,
|
|
105
112
|
)
|
|
106
113
|
|
|
@@ -120,10 +127,11 @@ async def check_non_processed_images(
|
|
|
120
127
|
# Skip check if previous task is converter
|
|
121
128
|
return JSONResponse(status_code=200, content=[])
|
|
122
129
|
|
|
123
|
-
res = await
|
|
130
|
+
res = await _get_dataset_check_access(
|
|
124
131
|
project_id=project_id,
|
|
125
132
|
dataset_id=dataset_id,
|
|
126
133
|
user_id=user.id,
|
|
134
|
+
required_permissions=ProjectPermissions.READ,
|
|
127
135
|
db=db,
|
|
128
136
|
)
|
|
129
137
|
dataset = res["dataset"]
|