fractal-server 2.17.2__tar.gz → 2.18.0a0__tar.gz
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-2.17.2 → fractal_server-2.18.0a0}/PKG-INFO +3 -2
- fractal_server-2.18.0a0/fractal_server/__init__.py +1 -0
- fractal_server-2.18.0a0/fractal_server/app/models/linkuserproject.py +53 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/__init__.py +2 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/job.py +17 -6
- fractal_server-2.18.0a0/fractal_server/app/routes/admin/v2/sharing.py +103 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/task.py +1 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/__init__.py +2 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/_aux_functions.py +43 -17
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/_aux_functions_history.py +8 -3
- fractal_server-2.18.0a0/fractal_server/app/routes/api/v2/_aux_functions_sharing.py +97 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/dataset.py +23 -17
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/history.py +21 -11
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/images.py +22 -8
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/job.py +28 -12
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/pre_submission_checks.py +13 -6
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/project.py +37 -14
- fractal_server-2.18.0a0/fractal_server/app/routes/api/v2/sharing.py +312 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/status_legacy.py +7 -4
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/submit.py +11 -5
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/task_version_update.py +7 -4
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/workflow.py +23 -11
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/workflow_import.py +14 -12
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/workflowtask.py +41 -7
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/__init__.py +7 -0
- fractal_server-2.18.0a0/fractal_server/app/schemas/v2/sharing.py +99 -0
- fractal_server-2.18.0a0/fractal_server/migrations/versions/bc0e8b3327a7_project_sharing.py +72 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/_batching.py +4 -10
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_ssh/runner.py +1 -1
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_sudo/runner.py +1 -1
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/pyproject.toml +3 -3
- fractal_server-2.17.2/fractal_server/__init__.py +0 -1
- fractal_server-2.17.2/fractal_server/app/models/linkuserproject.py +0 -13
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/LICENSE +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/README.md +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/__main__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/alembic.ini +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/db/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/linkusergroup.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/security.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/accounting.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/dataset.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/history.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/job.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/profile.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/project.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/resource.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/task.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/task_group.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/workflow.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/models/v2/workflowtask.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/_aux_functions.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/profile.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/resource.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/task.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/task_collection_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/task_group.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/current_user.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/group.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/login.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/oauth.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/register.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/router.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/auth/users.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/aux/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/aux/_job.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/aux/_runner.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/aux/validate_user_profile.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/pagination.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/user.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/user_group.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/accounting.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/dataset.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/dumps.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/history.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/job.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/manifest.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/profile.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/project.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/resource.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/task.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/task_collection.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/task_group.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/workflow.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/security/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/security/signup_email.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/shutdown.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/config/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/config/_data.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/config/_database.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/config/_email.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/config/_main.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/config/_oauth.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/config/_settings_config.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/data_migrations/README.md +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/data_migrations/tools.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/exceptions.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/gunicorn_fractal.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/images/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/images/models.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/images/status_tools.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/images/tools.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/logger.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/main.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/env.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/naming_convention.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/1a83a5260664_rename.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/40d6d6511b20_add_index_to_history_models.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/45fbb391d7af_make_resource_id_fk_non_nullable.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/49d0856e9569_drop_table.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/7673fe18c05d_remove_project_dir_server_default.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/caba9fb1ea5e_drop_useroauth_user_settings_id.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/e0e717ae2f26_delete_linkuserproject_ondelete_project.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/py.typed +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/components.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/config/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/config/_local.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/config/_slurm.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/config/slurm_mem_to_MB.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/exceptions.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/base_runner.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/call_command_wrapper.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/local/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/local/get_local_config.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/local/runner.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/_job_states.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/base_slurm_runner.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/get_slurm_config.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/remote.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/slurm_config.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_ssh/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_ssh/run_subprocess.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_ssh/tar_commands.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_sudo/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/filenames.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/set_start_and_last_task_index.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/task_files.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/_local.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/_slurm_ssh.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/_slurm_sudo.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/db_tools.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/deduplicate_list.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/merge_outputs.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/runner.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/runner_functions.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/submit_workflow.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/v2/task_interface.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/runner/versions.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/ssh/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/ssh/_fabric.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/string_tools.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/syringe.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/config/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/config/_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/config/_python.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/utils.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/_utils.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/collect.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/collect_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/deactivate.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/delete.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/reactivate.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/local/reactivate_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/collect.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/collect_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/delete.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/pixi_2_install.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/utils_background.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/utils_database.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/utils_package_names.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/utils_pixi.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/tasks/v2/utils_templates.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/types/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/types/validators/__init__.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/types/validators/_common_validators.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/types/validators/_filter_validators.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/urls.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/utils.py +0 -0
- {fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/zip_tools.py +0 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fractal-server
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.18.0a0
|
|
4
4
|
Summary: Backend component of the Fractal analytics platform
|
|
5
5
|
License-Expression: BSD-3-Clause
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Author: Tommaso Comparin
|
|
8
8
|
Author-email: tommaso.comparin@exact-lab.it
|
|
9
|
-
Requires-Python: >=3.11,<3.
|
|
9
|
+
Requires-Python: >=3.11,<3.15
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
15
|
Requires-Dist: alembic (>=1.13.1,<2.0.0)
|
|
15
16
|
Requires-Dist: fabric (>=3.2.2,<3.3.0)
|
|
16
17
|
Requires-Dist: fastapi (>=0.120.0,<0.121.0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__VERSION__ = "2.18.0a0"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from sqlmodel import BOOLEAN
|
|
2
|
+
from sqlmodel import CheckConstraint
|
|
3
|
+
from sqlmodel import Column
|
|
4
|
+
from sqlmodel import Field
|
|
5
|
+
from sqlmodel import Index
|
|
6
|
+
from sqlmodel import SQLModel
|
|
7
|
+
from sqlmodel import String
|
|
8
|
+
from sqlmodel import column
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LinkUserProjectV2(SQLModel, table=True):
|
|
12
|
+
"""
|
|
13
|
+
Crossing table between User and ProjectV2
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
project_id: int = Field(
|
|
17
|
+
foreign_key="projectv2.id", primary_key=True, ondelete="CASCADE"
|
|
18
|
+
)
|
|
19
|
+
user_id: int = Field(foreign_key="user_oauth.id", primary_key=True)
|
|
20
|
+
|
|
21
|
+
# TODO-2.18.1 drop server_default
|
|
22
|
+
is_owner: bool = Field(
|
|
23
|
+
sa_column=Column(BOOLEAN, server_default="true", nullable=False)
|
|
24
|
+
)
|
|
25
|
+
# TODO-2.18.1 drop server_default
|
|
26
|
+
is_verified: bool = Field(
|
|
27
|
+
sa_column=Column(BOOLEAN, server_default="true", nullable=False)
|
|
28
|
+
)
|
|
29
|
+
# TODO-2.18.1 drop server_default
|
|
30
|
+
permissions: str = Field(
|
|
31
|
+
sa_column=Column(String, server_default="'rwx'", nullable=False)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__table_args__ = (
|
|
35
|
+
Index(
|
|
36
|
+
"ix_linkuserprojectv2_one_owner_per_project",
|
|
37
|
+
"project_id",
|
|
38
|
+
unique=True,
|
|
39
|
+
postgresql_where=column("is_owner").is_(True),
|
|
40
|
+
),
|
|
41
|
+
CheckConstraint(
|
|
42
|
+
"NOT (is_owner AND NOT is_verified)",
|
|
43
|
+
name="owner_is_verified",
|
|
44
|
+
),
|
|
45
|
+
CheckConstraint(
|
|
46
|
+
"NOT (is_owner AND permissions <> 'rwx')",
|
|
47
|
+
name="owner_full_permissions",
|
|
48
|
+
),
|
|
49
|
+
CheckConstraint(
|
|
50
|
+
"permissions IN ('r', 'rw', 'rwx')",
|
|
51
|
+
name="valid_permissions",
|
|
52
|
+
),
|
|
53
|
+
)
|
{fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/__init__.py
RENAMED
|
@@ -9,6 +9,7 @@ from .impersonate import router as impersonate_router
|
|
|
9
9
|
from .job import router as job_router
|
|
10
10
|
from .profile import router as profile_router
|
|
11
11
|
from .resource import router as resource_router
|
|
12
|
+
from .sharing import router as sharing_router
|
|
12
13
|
from .task import router as task_router
|
|
13
14
|
from .task_group import router as task_group_router
|
|
14
15
|
from .task_group_lifecycle import router as task_group_lifecycle_router
|
|
@@ -25,3 +26,4 @@ router_admin_v2.include_router(
|
|
|
25
26
|
router_admin_v2.include_router(impersonate_router, prefix="/impersonate")
|
|
26
27
|
router_admin_v2.include_router(resource_router, prefix="/resource")
|
|
27
28
|
router_admin_v2.include_router(profile_router, prefix="/profile")
|
|
29
|
+
router_admin_v2.include_router(sharing_router, prefix="/linkuserproject")
|
|
@@ -56,6 +56,7 @@ async def view_job(
|
|
|
56
56
|
|
|
57
57
|
Args:
|
|
58
58
|
id: If not `None`, select a given `applyworkflow.id`.
|
|
59
|
+
user_id:
|
|
59
60
|
project_id: If not `None`, select a given `applyworkflow.project_id`.
|
|
60
61
|
dataset_id: If not `None`, select a given
|
|
61
62
|
`applyworkflow.input_dataset_id`.
|
|
@@ -84,12 +85,22 @@ async def view_job(
|
|
|
84
85
|
stm = stm.where(JobV2.id == id)
|
|
85
86
|
stm_count = stm_count.where(JobV2.id == id)
|
|
86
87
|
if user_id is not None:
|
|
87
|
-
stm =
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
stm = (
|
|
89
|
+
stm.join(
|
|
90
|
+
LinkUserProjectV2,
|
|
91
|
+
LinkUserProjectV2.project_id == JobV2.project_id,
|
|
92
|
+
)
|
|
93
|
+
.where(LinkUserProjectV2.user_id == user_id)
|
|
94
|
+
.where(LinkUserProjectV2.is_owner.is_(True))
|
|
95
|
+
)
|
|
96
|
+
stm_count = (
|
|
97
|
+
stm_count.join(
|
|
98
|
+
LinkUserProjectV2,
|
|
99
|
+
LinkUserProjectV2.project_id == JobV2.project_id,
|
|
100
|
+
)
|
|
101
|
+
.where(LinkUserProjectV2.user_id == user_id)
|
|
102
|
+
.where(LinkUserProjectV2.is_owner.is_(True))
|
|
103
|
+
)
|
|
93
104
|
if project_id is not None:
|
|
94
105
|
stm = stm.where(JobV2.project_id == project_id)
|
|
95
106
|
stm_count = stm_count.where(JobV2.project_id == project_id)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from fastapi import APIRouter
|
|
2
|
+
from fastapi import Depends
|
|
3
|
+
from sqlalchemy import func
|
|
4
|
+
from sqlmodel import select
|
|
5
|
+
|
|
6
|
+
from fractal_server.app.db import AsyncSession
|
|
7
|
+
from fractal_server.app.db import get_async_db
|
|
8
|
+
from fractal_server.app.models import LinkUserProjectV2
|
|
9
|
+
from fractal_server.app.models import UserOAuth
|
|
10
|
+
from fractal_server.app.models.v2 import ProjectV2
|
|
11
|
+
from fractal_server.app.routes.auth import current_superuser_act
|
|
12
|
+
from fractal_server.app.routes.pagination import PaginationRequest
|
|
13
|
+
from fractal_server.app.routes.pagination import PaginationResponse
|
|
14
|
+
from fractal_server.app.routes.pagination import get_pagination_params
|
|
15
|
+
from fractal_server.app.schemas.v2 import LinkUserProjectRead
|
|
16
|
+
|
|
17
|
+
router = APIRouter()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@router.get("/", response_model=PaginationResponse[LinkUserProjectRead])
|
|
21
|
+
async def view_link_user_project(
|
|
22
|
+
# User info
|
|
23
|
+
user_id: int | None = None,
|
|
24
|
+
# Project info
|
|
25
|
+
project_id: int | None = None,
|
|
26
|
+
project_name: str | None = None,
|
|
27
|
+
# Permissions
|
|
28
|
+
is_owner: bool | None = None,
|
|
29
|
+
is_verified: bool | None = None,
|
|
30
|
+
# -----
|
|
31
|
+
pagination: PaginationRequest = Depends(get_pagination_params),
|
|
32
|
+
superuser: UserOAuth = Depends(current_superuser_act),
|
|
33
|
+
db: AsyncSession = Depends(get_async_db),
|
|
34
|
+
) -> PaginationResponse[LinkUserProjectRead]:
|
|
35
|
+
page = pagination.page
|
|
36
|
+
page_size = pagination.page_size
|
|
37
|
+
|
|
38
|
+
stm = (
|
|
39
|
+
select(
|
|
40
|
+
LinkUserProjectV2,
|
|
41
|
+
UserOAuth.email,
|
|
42
|
+
ProjectV2.name,
|
|
43
|
+
)
|
|
44
|
+
.join(UserOAuth, UserOAuth.id == LinkUserProjectV2.user_id)
|
|
45
|
+
.join(ProjectV2, ProjectV2.id == LinkUserProjectV2.project_id)
|
|
46
|
+
.order_by(UserOAuth.email, ProjectV2.name)
|
|
47
|
+
)
|
|
48
|
+
stm_count = (
|
|
49
|
+
select(func.count())
|
|
50
|
+
.select_from(LinkUserProjectV2)
|
|
51
|
+
.join(UserOAuth, UserOAuth.id == LinkUserProjectV2.user_id)
|
|
52
|
+
.join(ProjectV2, ProjectV2.id == LinkUserProjectV2.project_id)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if project_id is not None:
|
|
56
|
+
stm = stm.where(LinkUserProjectV2.project_id == project_id)
|
|
57
|
+
stm_count = stm_count.where(LinkUserProjectV2.project_id == project_id)
|
|
58
|
+
if project_name is not None:
|
|
59
|
+
stm = stm.where(ProjectV2.name.icontains(project_name))
|
|
60
|
+
stm_count = stm_count.where(ProjectV2.name.icontains(project_name))
|
|
61
|
+
if user_id is not None:
|
|
62
|
+
stm = stm.where(LinkUserProjectV2.user_id == user_id)
|
|
63
|
+
stm_count = stm_count.where(LinkUserProjectV2.user_id == user_id)
|
|
64
|
+
if is_owner is not None:
|
|
65
|
+
stm = stm.where(LinkUserProjectV2.is_owner == is_owner)
|
|
66
|
+
stm_count = stm_count.where(LinkUserProjectV2.is_owner == is_owner)
|
|
67
|
+
if is_verified is not None:
|
|
68
|
+
stm = stm.where(LinkUserProjectV2.is_verified == is_verified)
|
|
69
|
+
stm_count = stm_count.where(
|
|
70
|
+
LinkUserProjectV2.is_verified == is_verified
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
res_total_count = await db.execute(stm_count)
|
|
74
|
+
|
|
75
|
+
total_count = res_total_count.scalar()
|
|
76
|
+
if page_size is None:
|
|
77
|
+
page_size = total_count
|
|
78
|
+
else:
|
|
79
|
+
stm = stm.offset((page - 1) * page_size).limit(page_size)
|
|
80
|
+
|
|
81
|
+
res = await db.execute(stm)
|
|
82
|
+
items = res.all()
|
|
83
|
+
|
|
84
|
+
return PaginationResponse[LinkUserProjectRead](
|
|
85
|
+
total_count=total_count,
|
|
86
|
+
page_size=page_size,
|
|
87
|
+
current_page=page,
|
|
88
|
+
items=[
|
|
89
|
+
dict(
|
|
90
|
+
# User info
|
|
91
|
+
user_id=linkuserproject.user_id,
|
|
92
|
+
user_email=user_email,
|
|
93
|
+
# Project info
|
|
94
|
+
project_id=linkuserproject.project_id,
|
|
95
|
+
project_name=project_name,
|
|
96
|
+
# Permissions
|
|
97
|
+
is_verified=linkuserproject.is_verified,
|
|
98
|
+
is_owner=linkuserproject.is_owner,
|
|
99
|
+
permissions=linkuserproject.permissions,
|
|
100
|
+
)
|
|
101
|
+
for linkuserproject, user_email, project_name in items
|
|
102
|
+
],
|
|
103
|
+
)
|
{fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/admin/v2/task.py
RENAMED
|
@@ -148,6 +148,7 @@ async def query_tasks(
|
|
|
148
148
|
LinkUserProjectV2.user_id == UserOAuth.id,
|
|
149
149
|
)
|
|
150
150
|
.where(LinkUserProjectV2.project_id == project_id)
|
|
151
|
+
.where(LinkUserProjectV2.is_owner.is_(True))
|
|
151
152
|
)
|
|
152
153
|
project_users[project_id] = [
|
|
153
154
|
ProjectUser(id=p_user[0], email=p_user[1])
|
{fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/__init__.py
RENAMED
|
@@ -13,6 +13,7 @@ from .images import router as images_routes_v2
|
|
|
13
13
|
from .job import router as job_router_v2
|
|
14
14
|
from .pre_submission_checks import router as pre_submission_checks_router
|
|
15
15
|
from .project import router as project_router_v2
|
|
16
|
+
from .sharing import router as sharing_router_v2
|
|
16
17
|
from .status_legacy import router as status_legacy_router_v2
|
|
17
18
|
from .submit import router as submit_job_router_v2
|
|
18
19
|
from .task import router as task_router_v2
|
|
@@ -32,6 +33,7 @@ router_api_v2.include_router(dataset_router_v2, tags=["V2 Dataset"])
|
|
|
32
33
|
router_api_v2.include_router(pre_submission_checks_router, tags=["V2 Job"])
|
|
33
34
|
router_api_v2.include_router(job_router_v2, tags=["V2 Job"])
|
|
34
35
|
router_api_v2.include_router(images_routes_v2, tags=["V2 Images"])
|
|
36
|
+
router_api_v2.include_router(sharing_router_v2, tags=["Project Sharing"])
|
|
35
37
|
router_api_v2.include_router(project_router_v2, tags=["V2 Project"])
|
|
36
38
|
router_api_v2.include_router(submit_job_router_v2, tags=["V2 Job"])
|
|
37
39
|
router_api_v2.include_router(history_router_v2, tags=["V2 History"])
|
{fractal_server-2.17.2 → fractal_server-2.18.0a0}/fractal_server/app/routes/api/v2/_aux_functions.py
RENAMED
|
@@ -24,15 +24,17 @@ from fractal_server.app.models.v2 import TaskV2
|
|
|
24
24
|
from fractal_server.app.models.v2 import WorkflowTaskV2
|
|
25
25
|
from fractal_server.app.models.v2 import WorkflowV2
|
|
26
26
|
from fractal_server.app.schemas.v2 import JobStatusTypeV2
|
|
27
|
+
from fractal_server.app.schemas.v2 import ProjectPermissions
|
|
27
28
|
from fractal_server.logger import set_logger
|
|
28
29
|
|
|
29
30
|
logger = set_logger(__name__)
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
async def
|
|
33
|
+
async def _get_project_check_access(
|
|
33
34
|
*,
|
|
34
35
|
project_id: int,
|
|
35
36
|
user_id: int,
|
|
37
|
+
required_permissions: ProjectPermissions,
|
|
36
38
|
db: AsyncSession,
|
|
37
39
|
) -> ProjectV2:
|
|
38
40
|
"""
|
|
@@ -41,6 +43,7 @@ async def _get_project_check_owner(
|
|
|
41
43
|
Args:
|
|
42
44
|
project_id:
|
|
43
45
|
user_id:
|
|
46
|
+
required_permissions:
|
|
44
47
|
db:
|
|
45
48
|
|
|
46
49
|
Returns:
|
|
@@ -48,31 +51,42 @@ async def _get_project_check_owner(
|
|
|
48
51
|
|
|
49
52
|
Raises:
|
|
50
53
|
HTTPException(status_code=403_FORBIDDEN):
|
|
51
|
-
If the user is not a member of the project
|
|
54
|
+
- If the user is not a member of the project;
|
|
55
|
+
- If the user has not accepted the invitation yet;
|
|
56
|
+
- If the user has not the target permissions.
|
|
52
57
|
HTTPException(status_code=404_NOT_FOUND):
|
|
53
58
|
If the project does not exist
|
|
54
59
|
"""
|
|
55
60
|
project = await db.get(ProjectV2, project_id)
|
|
56
|
-
|
|
57
|
-
link_user_project = await db.get(LinkUserProjectV2, (project_id, user_id))
|
|
58
|
-
if not project:
|
|
61
|
+
if project is None:
|
|
59
62
|
raise HTTPException(
|
|
60
63
|
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
|
|
61
64
|
)
|
|
62
|
-
|
|
65
|
+
|
|
66
|
+
link_user_project = await db.get(LinkUserProjectV2, (project_id, user_id))
|
|
67
|
+
if (
|
|
68
|
+
link_user_project is None
|
|
69
|
+
or not link_user_project.is_verified
|
|
70
|
+
or required_permissions not in link_user_project.permissions
|
|
71
|
+
):
|
|
63
72
|
raise HTTPException(
|
|
64
73
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
65
|
-
detail=
|
|
74
|
+
detail=(
|
|
75
|
+
"You are not authorized to perform this action. "
|
|
76
|
+
"If you think this is by mistake, "
|
|
77
|
+
"please contact the project owner."
|
|
78
|
+
),
|
|
66
79
|
)
|
|
67
80
|
|
|
68
81
|
return project
|
|
69
82
|
|
|
70
83
|
|
|
71
|
-
async def
|
|
84
|
+
async def _get_workflow_check_access(
|
|
72
85
|
*,
|
|
73
86
|
workflow_id: int,
|
|
74
87
|
project_id: int,
|
|
75
88
|
user_id: int,
|
|
89
|
+
required_permissions: ProjectPermissions,
|
|
76
90
|
db: AsyncSession,
|
|
77
91
|
) -> WorkflowV2:
|
|
78
92
|
"""
|
|
@@ -96,8 +110,11 @@ async def _get_workflow_check_owner(
|
|
|
96
110
|
"""
|
|
97
111
|
|
|
98
112
|
# Access control for project
|
|
99
|
-
await
|
|
100
|
-
project_id=project_id,
|
|
113
|
+
await _get_project_check_access(
|
|
114
|
+
project_id=project_id,
|
|
115
|
+
user_id=user_id,
|
|
116
|
+
required_permissions=required_permissions,
|
|
117
|
+
db=db,
|
|
101
118
|
)
|
|
102
119
|
|
|
103
120
|
res = await db.execute(
|
|
@@ -116,12 +133,13 @@ async def _get_workflow_check_owner(
|
|
|
116
133
|
return workflow
|
|
117
134
|
|
|
118
135
|
|
|
119
|
-
async def
|
|
136
|
+
async def _get_workflow_task_check_access(
|
|
120
137
|
*,
|
|
121
138
|
project_id: int,
|
|
122
139
|
workflow_id: int,
|
|
123
140
|
workflow_task_id: int,
|
|
124
141
|
user_id: int,
|
|
142
|
+
required_permissions: ProjectPermissions,
|
|
125
143
|
db: AsyncSession,
|
|
126
144
|
) -> tuple[WorkflowTaskV2, WorkflowV2]:
|
|
127
145
|
"""
|
|
@@ -146,10 +164,11 @@ async def _get_workflow_task_check_owner(
|
|
|
146
164
|
"""
|
|
147
165
|
|
|
148
166
|
# Access control for workflow
|
|
149
|
-
workflow = await
|
|
167
|
+
workflow = await _get_workflow_check_access(
|
|
150
168
|
workflow_id=workflow_id,
|
|
151
169
|
project_id=project_id,
|
|
152
170
|
user_id=user_id,
|
|
171
|
+
required_permissions=required_permissions,
|
|
153
172
|
db=db,
|
|
154
173
|
)
|
|
155
174
|
|
|
@@ -223,6 +242,7 @@ async def _check_project_exists(
|
|
|
223
242
|
.join(LinkUserProjectV2, LinkUserProjectV2.project_id == ProjectV2.id)
|
|
224
243
|
.where(ProjectV2.name == project_name)
|
|
225
244
|
.where(LinkUserProjectV2.user_id == user_id)
|
|
245
|
+
.where(LinkUserProjectV2.is_owner.is_(True))
|
|
226
246
|
)
|
|
227
247
|
res = await db.execute(stm)
|
|
228
248
|
if res.scalars().all():
|
|
@@ -232,11 +252,12 @@ async def _check_project_exists(
|
|
|
232
252
|
)
|
|
233
253
|
|
|
234
254
|
|
|
235
|
-
async def
|
|
255
|
+
async def _get_dataset_check_access(
|
|
236
256
|
*,
|
|
237
257
|
project_id: int,
|
|
238
258
|
dataset_id: int,
|
|
239
259
|
user_id: int,
|
|
260
|
+
required_permissions: ProjectPermissions,
|
|
240
261
|
db: AsyncSession,
|
|
241
262
|
) -> dict[Literal["dataset", "project"], DatasetV2 | ProjectV2]:
|
|
242
263
|
"""
|
|
@@ -260,8 +281,11 @@ async def _get_dataset_check_owner(
|
|
|
260
281
|
If the user is not a member of the project
|
|
261
282
|
"""
|
|
262
283
|
# Access control for project
|
|
263
|
-
project = await
|
|
264
|
-
project_id=project_id,
|
|
284
|
+
project = await _get_project_check_access(
|
|
285
|
+
project_id=project_id,
|
|
286
|
+
user_id=user_id,
|
|
287
|
+
required_permissions=required_permissions,
|
|
288
|
+
db=db,
|
|
265
289
|
)
|
|
266
290
|
|
|
267
291
|
res = await db.execute(
|
|
@@ -280,11 +304,12 @@ async def _get_dataset_check_owner(
|
|
|
280
304
|
return dict(dataset=dataset, project=project)
|
|
281
305
|
|
|
282
306
|
|
|
283
|
-
async def
|
|
307
|
+
async def _get_job_check_access(
|
|
284
308
|
*,
|
|
285
309
|
project_id: int,
|
|
286
310
|
job_id: int,
|
|
287
311
|
user_id: int,
|
|
312
|
+
required_permissions: ProjectPermissions,
|
|
288
313
|
db: AsyncSession,
|
|
289
314
|
) -> dict[Literal["job", "project"], JobV2 | ProjectV2]:
|
|
290
315
|
"""
|
|
@@ -308,9 +333,10 @@ async def _get_job_check_owner(
|
|
|
308
333
|
If the user is not a member of the project
|
|
309
334
|
"""
|
|
310
335
|
# Access control for project
|
|
311
|
-
project = await
|
|
336
|
+
project = await _get_project_check_access(
|
|
312
337
|
project_id=project_id,
|
|
313
338
|
user_id=user_id,
|
|
339
|
+
required_permissions=required_permissions,
|
|
314
340
|
db=db,
|
|
315
341
|
)
|
|
316
342
|
|
|
@@ -13,12 +13,13 @@ from fractal_server.app.models.v2 import HistoryUnit
|
|
|
13
13
|
from fractal_server.app.models.v2 import WorkflowV2
|
|
14
14
|
from fractal_server.app.routes.api.v2._aux_functions import _get_dataset_or_404
|
|
15
15
|
from fractal_server.app.routes.api.v2._aux_functions import (
|
|
16
|
-
|
|
16
|
+
_get_project_check_access,
|
|
17
17
|
)
|
|
18
18
|
from fractal_server.app.routes.api.v2._aux_functions import _get_workflow_or_404
|
|
19
19
|
from fractal_server.app.routes.api.v2._aux_functions import (
|
|
20
20
|
_get_workflowtask_or_404,
|
|
21
21
|
)
|
|
22
|
+
from fractal_server.app.schemas.v2.sharing import ProjectPermissions
|
|
22
23
|
from fractal_server.logger import set_logger
|
|
23
24
|
from fractal_server.zip_tools import _read_single_file_from_zip
|
|
24
25
|
|
|
@@ -119,6 +120,7 @@ async def _verify_workflow_and_dataset_access(
|
|
|
119
120
|
workflow_id: int,
|
|
120
121
|
dataset_id: int,
|
|
121
122
|
user_id: int,
|
|
123
|
+
required_permissions: ProjectPermissions,
|
|
122
124
|
db: AsyncSession,
|
|
123
125
|
) -> dict[Literal["dataset", "workflow"], DatasetV2 | WorkflowV2]:
|
|
124
126
|
"""
|
|
@@ -131,9 +133,10 @@ async def _verify_workflow_and_dataset_access(
|
|
|
131
133
|
user_id:
|
|
132
134
|
db:
|
|
133
135
|
"""
|
|
134
|
-
await
|
|
136
|
+
await _get_project_check_access(
|
|
135
137
|
project_id=project_id,
|
|
136
138
|
user_id=user_id,
|
|
139
|
+
required_permissions=required_permissions,
|
|
137
140
|
db=db,
|
|
138
141
|
)
|
|
139
142
|
workflow = await _get_workflow_or_404(
|
|
@@ -158,12 +161,13 @@ async def _verify_workflow_and_dataset_access(
|
|
|
158
161
|
return dict(dataset=dataset, workflow=workflow)
|
|
159
162
|
|
|
160
163
|
|
|
161
|
-
async def
|
|
164
|
+
async def get_wftask_check_access(
|
|
162
165
|
*,
|
|
163
166
|
project_id: int,
|
|
164
167
|
dataset_id: int,
|
|
165
168
|
workflowtask_id: int,
|
|
166
169
|
user_id: int,
|
|
170
|
+
required_permissions: ProjectPermissions,
|
|
167
171
|
db: AsyncSession,
|
|
168
172
|
) -> WorkflowTaskV2:
|
|
169
173
|
"""
|
|
@@ -184,6 +188,7 @@ async def get_wftask_check_owner(
|
|
|
184
188
|
project_id=project_id,
|
|
185
189
|
dataset_id=dataset_id,
|
|
186
190
|
workflow_id=wftask.workflow_id,
|
|
191
|
+
required_permissions=required_permissions,
|
|
187
192
|
user_id=user_id,
|
|
188
193
|
db=db,
|
|
189
194
|
)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from fastapi import HTTPException
|
|
2
|
+
from fastapi import status
|
|
3
|
+
from sqlmodel import select
|
|
4
|
+
|
|
5
|
+
from fractal_server.app.db import AsyncSession
|
|
6
|
+
from fractal_server.app.models import UserOAuth
|
|
7
|
+
from fractal_server.app.models.v2 import LinkUserProjectV2
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def raise_403_if_not_owner(
|
|
11
|
+
*,
|
|
12
|
+
user_id: int,
|
|
13
|
+
project_id: int,
|
|
14
|
+
db: AsyncSession,
|
|
15
|
+
) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Raises 403 if User[`user_id`] is not owner of Project[`project_id`],
|
|
18
|
+
regardless of whether the User or Project exists.
|
|
19
|
+
"""
|
|
20
|
+
res = await db.execute(
|
|
21
|
+
select(LinkUserProjectV2)
|
|
22
|
+
.where(LinkUserProjectV2.project_id == project_id)
|
|
23
|
+
.where(LinkUserProjectV2.user_id == user_id)
|
|
24
|
+
.where(LinkUserProjectV2.is_owner.is_(True))
|
|
25
|
+
)
|
|
26
|
+
link = res.scalars().one_or_none()
|
|
27
|
+
if link is None:
|
|
28
|
+
raise HTTPException(
|
|
29
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
30
|
+
detail="Current user is not the project owner.",
|
|
31
|
+
)
|
|
32
|
+
return link
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def get_link_or_404(
|
|
36
|
+
*, user_id: int, project_id: int, db: AsyncSession
|
|
37
|
+
) -> LinkUserProjectV2:
|
|
38
|
+
"""
|
|
39
|
+
Raises 404 if User[`user_id`] is not linked to Project[`project_id`],
|
|
40
|
+
regardless of whether the User or Project exists.
|
|
41
|
+
"""
|
|
42
|
+
link = await db.get(LinkUserProjectV2, (project_id, user_id))
|
|
43
|
+
if link is None:
|
|
44
|
+
raise HTTPException(
|
|
45
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
46
|
+
detail="User is not linked to project.",
|
|
47
|
+
)
|
|
48
|
+
return link
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def get_pending_invitation_or_404(
|
|
52
|
+
*, user_id: int, project_id: int, db: AsyncSession
|
|
53
|
+
) -> LinkUserProjectV2:
|
|
54
|
+
"""
|
|
55
|
+
Raises 404 if User[`user_id`] has not a pending invitation to
|
|
56
|
+
Project[`project_id`], regardless of whether the User or Project exists.
|
|
57
|
+
"""
|
|
58
|
+
link = await get_link_or_404(user_id=user_id, project_id=project_id, db=db)
|
|
59
|
+
if link.is_verified:
|
|
60
|
+
raise HTTPException(
|
|
61
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
62
|
+
detail="No pending invitation for user on this project.",
|
|
63
|
+
)
|
|
64
|
+
return link
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def raise_422_if_link_exists(
|
|
68
|
+
*, user_id: int, project_id: int, db: AsyncSession
|
|
69
|
+
) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Raises 422 if User[`user_id`] is linked Project[`project_id`], regardless
|
|
72
|
+
of whether the User or Project exists.
|
|
73
|
+
"""
|
|
74
|
+
link = await db.get(LinkUserProjectV2, (project_id, user_id))
|
|
75
|
+
if link is not None:
|
|
76
|
+
raise HTTPException(
|
|
77
|
+
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
78
|
+
detail="User is already associated to project.",
|
|
79
|
+
)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
async def get_user_id_from_email_or_404(
|
|
84
|
+
*, user_email: str, db: AsyncSession
|
|
85
|
+
) -> int:
|
|
86
|
+
"""
|
|
87
|
+
Raises 404 if there is no User with email `user_email`.
|
|
88
|
+
"""
|
|
89
|
+
res = await db.execute(
|
|
90
|
+
select(UserOAuth.id).where(UserOAuth.email == user_email)
|
|
91
|
+
)
|
|
92
|
+
user_id = res.scalar_one_or_none()
|
|
93
|
+
if user_id is None:
|
|
94
|
+
raise HTTPException(
|
|
95
|
+
status_code=status.HTTP_404_NOT_FOUND, detail="User not found."
|
|
96
|
+
)
|
|
97
|
+
return user_id
|