fractal-server 2.17.0a6__tar.gz → 2.17.0a8__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.0a6 → fractal_server-2.17.0a8}/PKG-INFO +1 -1
- fractal_server-2.17.0a8/fractal_server/__init__.py +1 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/security.py +7 -1
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/user_settings.py +4 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/profile.py +1 -1
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/project.py +3 -1
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/resource.py +2 -2
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/task_group.py +1 -1
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/resource.py +9 -52
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/_aux_functions.py +6 -16
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +36 -8
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/project.py +8 -4
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/submit.py +3 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task.py +18 -5
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task_collection.py +3 -5
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task_collection_custom.py +2 -5
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task_collection_pixi.py +2 -5
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/oauth.py +16 -6
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/config/_main.py +1 -1
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/naming_convention.py +1 -1
- fractal_server-2.17.0a6/fractal_server/migrations/versions/a80ac5a352bf_resource_profile.py → fractal_server-2.17.0a8/fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +31 -31
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/pyproject.toml +3 -3
- fractal_server-2.17.0a6/fractal_server/__init__.py +0 -1
- fractal_server-2.17.0a6/fractal_server/data_migrations/2_14_10.py +0 -48
- fractal_server-2.17.0a6/fractal_server/migrations/versions/90f6508c6379_drop_useroauth_username.py +0 -36
- fractal_server-2.17.0a6/fractal_server/migrations/versions/f65ee53991e3_user_settings_related.py +0 -67
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/LICENSE +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/README.md +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/__main__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/alembic.ini +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/db/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/linkusergroup.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/linkuserproject.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/accounting.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/dataset.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/history.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/job.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/task.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/workflow.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/workflowtask.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/_aux_functions.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/job.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/profile.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/project.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/task.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/dataset.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/history.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/images.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/job.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task_group.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task_version_update.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/workflow.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/current_user.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/group.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/login.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/register.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/router.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/auth/users.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/aux/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/aux/_job.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/aux/_runner.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/aux/validate_user_profile.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/pagination.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/user.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/user_group.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/accounting.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/dataset.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/dumps.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/history.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/job.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/manifest.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/profile.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/project.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/resource.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/task.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/task_collection.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/task_group.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/workflow.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/security/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/security/signup_email.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/shutdown.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/config/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/config/_data.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/config/_database.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/config/_email.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/config/_oauth.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/config/_settings_config.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/data_migrations/README.md +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/data_migrations/tools.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/exceptions.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/gunicorn_fractal.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/images/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/images/models.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/images/status_tools.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/images/tools.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/logger.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/main.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/env.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/1a83a5260664_rename.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/py.typed +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/components.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/config/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/config/_local.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/config/_slurm.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/config/slurm_mem_to_MB.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/exceptions.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/base_runner.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/call_command_wrapper.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/local/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/local/get_local_config.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/local/runner.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/_batching.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/_job_states.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/base_slurm_runner.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/get_slurm_config.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/remote.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/slurm_config.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_ssh/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_ssh/run_subprocess.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_ssh/runner.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_ssh/tar_commands.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_sudo/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/executors/slurm_sudo/runner.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/filenames.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/set_start_and_last_task_index.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/task_files.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/_local.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/_slurm_ssh.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/_slurm_sudo.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/db_tools.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/deduplicate_list.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/merge_outputs.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/runner.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/runner_functions.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/submit_workflow.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/v2/task_interface.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/runner/versions.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/ssh/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/ssh/_fabric.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/string_tools.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/syringe.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/config/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/config/_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/config/_python.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/utils.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/_utils.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/collect.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/collect_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/deactivate.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/delete.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/reactivate.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/local/reactivate_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/collect.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/collect_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/delete.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/pixi_2_install.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/utils_background.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/utils_database.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/utils_package_names.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/utils_pixi.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/tasks/v2/utils_templates.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/types/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/types/validators/__init__.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/types/validators/_common_validators.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/types/validators/_filter_validators.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/urls.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/utils.py +0 -0
- {fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/zip_tools.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__VERSION__ = "2.17.0a8"
|
|
@@ -92,7 +92,7 @@ class UserOAuth(SQLModel, table=True):
|
|
|
92
92
|
profile_id: int | None = Field(
|
|
93
93
|
foreign_key="profile.id",
|
|
94
94
|
default=None,
|
|
95
|
-
ondelete="
|
|
95
|
+
ondelete="RESTRICT",
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
# TODO-2.17.1: update to `project_dir: str`
|
|
@@ -107,6 +107,12 @@ class UserOAuth(SQLModel, table=True):
|
|
|
107
107
|
sa_column=Column(ARRAY(String), server_default="{}"),
|
|
108
108
|
)
|
|
109
109
|
|
|
110
|
+
# TODO-2.17.1: remove
|
|
111
|
+
user_settings_id: int | None = Field(
|
|
112
|
+
foreign_key="user_settings.id",
|
|
113
|
+
default=None,
|
|
114
|
+
)
|
|
115
|
+
|
|
110
116
|
|
|
111
117
|
class UserGroup(SQLModel, table=True):
|
|
112
118
|
"""
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/user_settings.py
RENAMED
|
@@ -29,5 +29,9 @@ class UserSettings(SQLModel, table=True):
|
|
|
29
29
|
ssh_host: str | None = None
|
|
30
30
|
ssh_username: str | None = None
|
|
31
31
|
ssh_private_key_path: str | None = None
|
|
32
|
+
|
|
32
33
|
slurm_user: str | None = None
|
|
33
34
|
project_dir: str | None = None
|
|
35
|
+
|
|
36
|
+
ssh_tasks_dir: str | None = None
|
|
37
|
+
ssh_jobs_dir: str | None = None
|
|
@@ -4,7 +4,7 @@ from sqlmodel import SQLModel
|
|
|
4
4
|
|
|
5
5
|
class Profile(SQLModel, table=True):
|
|
6
6
|
id: int | None = Field(default=None, primary_key=True)
|
|
7
|
-
resource_id: int = Field(foreign_key="resource.id", ondelete="
|
|
7
|
+
resource_id: int = Field(foreign_key="resource.id", ondelete="RESTRICT")
|
|
8
8
|
resource_type: str
|
|
9
9
|
|
|
10
10
|
name: str = Field(unique=True)
|
|
@@ -14,8 +14,10 @@ from fractal_server.utils import get_timestamp
|
|
|
14
14
|
class ProjectV2(SQLModel, table=True):
|
|
15
15
|
id: int | None = Field(default=None, primary_key=True)
|
|
16
16
|
name: str
|
|
17
|
+
|
|
18
|
+
# TODO-2.17.1: make `resource_id` not nullable
|
|
17
19
|
resource_id: int | None = Field(
|
|
18
|
-
foreign_key="resource.id", default=None, ondelete="
|
|
20
|
+
foreign_key="resource.id", default=None, ondelete="RESTRICT"
|
|
19
21
|
)
|
|
20
22
|
timestamp_created: datetime = Field(
|
|
21
23
|
default_factory=get_timestamp,
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/resource.py
RENAMED
|
@@ -120,11 +120,11 @@ class Resource(SQLModel, table=True):
|
|
|
120
120
|
# `type` column must be one of "local", "slurm_sudo" or "slurm_ssh"
|
|
121
121
|
CheckConstraint(
|
|
122
122
|
"type IN ('local', 'slurm_sudo', 'slurm_ssh')",
|
|
123
|
-
name="
|
|
123
|
+
name="correct_type",
|
|
124
124
|
),
|
|
125
125
|
# If `type` is not "local", `jobs_slurm_python_worker` must be set
|
|
126
126
|
CheckConstraint(
|
|
127
127
|
"(type = 'local') OR (jobs_slurm_python_worker IS NOT NULL)",
|
|
128
|
-
name="
|
|
128
|
+
name="jobs_slurm_python_worker_set",
|
|
129
129
|
),
|
|
130
130
|
)
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/models/v2/task_group.py
RENAMED
|
@@ -44,7 +44,7 @@ class TaskGroupV2(SQLModel, table=True):
|
|
|
44
44
|
)
|
|
45
45
|
# TODO-2.17.1: make `resource_id` not nullable
|
|
46
46
|
resource_id: int | None = Field(
|
|
47
|
-
foreign_key="resource.id", default=None, ondelete="
|
|
47
|
+
foreign_key="resource.id", default=None, ondelete="RESTRICT"
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
origin: str
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/admin/v2/resource.py
RENAMED
|
@@ -3,7 +3,7 @@ from fastapi import Depends
|
|
|
3
3
|
from fastapi import HTTPException
|
|
4
4
|
from fastapi import Response
|
|
5
5
|
from fastapi import status
|
|
6
|
-
from
|
|
6
|
+
from sqlalchemy.exc import IntegrityError
|
|
7
7
|
from sqlmodel import select
|
|
8
8
|
|
|
9
9
|
from ._aux_functions import _check_resource_name
|
|
@@ -13,9 +13,7 @@ from fractal_server.app.db import AsyncSession
|
|
|
13
13
|
from fractal_server.app.db import get_async_db
|
|
14
14
|
from fractal_server.app.models import UserOAuth
|
|
15
15
|
from fractal_server.app.models.v2 import Profile
|
|
16
|
-
from fractal_server.app.models.v2 import ProjectV2
|
|
17
16
|
from fractal_server.app.models.v2 import Resource
|
|
18
|
-
from fractal_server.app.models.v2 import TaskGroupV2
|
|
19
17
|
from fractal_server.app.routes.auth import current_superuser_act
|
|
20
18
|
from fractal_server.app.schemas.v2 import ProfileCreate
|
|
21
19
|
from fractal_server.app.schemas.v2 import ProfileRead
|
|
@@ -151,61 +149,20 @@ async def delete_resource(
|
|
|
151
149
|
Delete single `Resource`.
|
|
152
150
|
"""
|
|
153
151
|
resource = await _get_resource_or_404(resource_id=resource_id, db=db)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
)
|
|
160
|
-
)
|
|
161
|
-
associated_profile_count = res.scalar()
|
|
162
|
-
if associated_profile_count > 0:
|
|
163
|
-
raise HTTPException(
|
|
164
|
-
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
165
|
-
detail=(
|
|
166
|
-
f"Cannot delete Resource {resource_id} because it's associated"
|
|
167
|
-
f" with {associated_profile_count} Profiles."
|
|
168
|
-
),
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
# Fail if at least one Project is associated with the Resource.
|
|
172
|
-
res = await db.execute(
|
|
173
|
-
select(func.count(ProjectV2.id)).where(
|
|
174
|
-
ProjectV2.resource_id == resource_id
|
|
175
|
-
)
|
|
176
|
-
)
|
|
177
|
-
associated_project_count = res.scalar()
|
|
178
|
-
if associated_project_count > 0:
|
|
152
|
+
try:
|
|
153
|
+
await db.delete(resource)
|
|
154
|
+
await db.commit()
|
|
155
|
+
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
|
156
|
+
except IntegrityError as e:
|
|
157
|
+
await db.rollback()
|
|
179
158
|
raise HTTPException(
|
|
180
159
|
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
181
160
|
detail=(
|
|
182
|
-
|
|
183
|
-
f"
|
|
161
|
+
"IntegrityError for resource deletion. "
|
|
162
|
+
f"Original error:\n{str(e)}"
|
|
184
163
|
),
|
|
185
164
|
)
|
|
186
165
|
|
|
187
|
-
# Fail if at least one TaskGroupV2 is associated with the Resource.
|
|
188
|
-
res = await db.execute(
|
|
189
|
-
select(func.count(TaskGroupV2.id)).where(
|
|
190
|
-
TaskGroupV2.resource_id == resource_id
|
|
191
|
-
)
|
|
192
|
-
)
|
|
193
|
-
associated_taskgroup_count = res.scalar()
|
|
194
|
-
if associated_taskgroup_count > 0:
|
|
195
|
-
raise HTTPException(
|
|
196
|
-
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
197
|
-
detail=(
|
|
198
|
-
f"Cannot delete Resource {resource_id} because it's associated"
|
|
199
|
-
f" with {associated_taskgroup_count} TaskGroupV2."
|
|
200
|
-
),
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
# Delete
|
|
204
|
-
await db.delete(resource)
|
|
205
|
-
await db.commit()
|
|
206
|
-
|
|
207
|
-
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
|
208
|
-
|
|
209
166
|
|
|
210
167
|
@router.get(
|
|
211
168
|
"/{resource_id}/profile/",
|
|
@@ -543,24 +543,14 @@ async def _get_submitted_job_or_none(
|
|
|
543
543
|
)
|
|
544
544
|
|
|
545
545
|
|
|
546
|
-
async def
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
) -> tuple[int, int] | tuple[None, None]:
|
|
551
|
-
"""
|
|
552
|
-
Get `(resource_id, profile_id)` pair for a given user, or `(None,None)`.
|
|
553
|
-
"""
|
|
554
|
-
stm = (
|
|
555
|
-
select(Resource.id, Profile.id)
|
|
546
|
+
async def _get_user_resource_id(user_id: int, db: AsyncSession) -> int | None:
|
|
547
|
+
res = await db.execute(
|
|
548
|
+
select(Resource.id)
|
|
549
|
+
.join(Profile)
|
|
556
550
|
.join(UserOAuth)
|
|
557
551
|
.where(Resource.id == Profile.resource_id)
|
|
558
552
|
.where(Profile.id == UserOAuth.profile_id)
|
|
559
553
|
.where(UserOAuth.id == user_id)
|
|
560
554
|
)
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
if data is None:
|
|
564
|
-
return (None, None)
|
|
565
|
-
else:
|
|
566
|
-
return tuple(data)
|
|
555
|
+
resource_id = res.scalar_one_or_none()
|
|
556
|
+
return resource_id
|
|
@@ -12,10 +12,14 @@ from fractal_server.app.db import AsyncSession
|
|
|
12
12
|
from fractal_server.app.models import LinkUserGroup
|
|
13
13
|
from fractal_server.app.models import UserGroup
|
|
14
14
|
from fractal_server.app.models import UserOAuth
|
|
15
|
+
from fractal_server.app.models.v2 import Profile
|
|
15
16
|
from fractal_server.app.models.v2 import TaskGroupActivityV2
|
|
16
17
|
from fractal_server.app.models.v2 import TaskGroupV2
|
|
17
18
|
from fractal_server.app.models.v2 import TaskV2
|
|
18
19
|
from fractal_server.app.models.v2 import WorkflowTaskV2
|
|
20
|
+
from fractal_server.app.routes.api.v2._aux_functions import (
|
|
21
|
+
_get_user_resource_id,
|
|
22
|
+
)
|
|
19
23
|
from fractal_server.app.routes.auth._aux_auth import _get_default_usergroup_id
|
|
20
24
|
from fractal_server.app.routes.auth._aux_auth import (
|
|
21
25
|
_verify_user_belongs_to_group,
|
|
@@ -80,11 +84,16 @@ async def _get_task_group_read_access(
|
|
|
80
84
|
else:
|
|
81
85
|
stm = (
|
|
82
86
|
select(LinkUserGroup)
|
|
87
|
+
.join(UserOAuth)
|
|
88
|
+
.join(Profile)
|
|
83
89
|
.where(LinkUserGroup.group_id == task_group.user_group_id)
|
|
84
90
|
.where(LinkUserGroup.user_id == user_id)
|
|
91
|
+
.where(UserOAuth.id == user_id)
|
|
92
|
+
.where(Profile.id == UserOAuth.profile_id)
|
|
93
|
+
.where(TaskGroupV2.resource_id == Profile.resource_id)
|
|
85
94
|
)
|
|
86
95
|
res = await db.execute(stm)
|
|
87
|
-
link = res.
|
|
96
|
+
link = res.unique().scalars().one_or_none()
|
|
88
97
|
if link is None:
|
|
89
98
|
raise forbidden_exception
|
|
90
99
|
else:
|
|
@@ -153,9 +162,17 @@ async def _get_task_full_access(
|
|
|
153
162
|
db: An asynchronous db session.
|
|
154
163
|
"""
|
|
155
164
|
task = await _get_task_or_404(task_id=task_id, db=db)
|
|
156
|
-
await _get_task_group_full_access(
|
|
165
|
+
task_group = await _get_task_group_full_access(
|
|
157
166
|
task_group_id=task.taskgroupv2_id, user_id=user_id, db=db
|
|
158
167
|
)
|
|
168
|
+
|
|
169
|
+
resource_id = await _get_user_resource_id(user_id=user_id, db=db)
|
|
170
|
+
if resource_id is None or resource_id != task_group.resource_id:
|
|
171
|
+
raise HTTPException(
|
|
172
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
173
|
+
detail=f"User {user_id} has no access to TaskGroup's Resource.",
|
|
174
|
+
)
|
|
175
|
+
|
|
159
176
|
return task
|
|
160
177
|
|
|
161
178
|
|
|
@@ -179,12 +196,20 @@ async def _get_task_read_access(
|
|
|
179
196
|
task_group = await _get_task_group_read_access(
|
|
180
197
|
task_group_id=task.taskgroupv2_id, user_id=user_id, db=db
|
|
181
198
|
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
199
|
+
|
|
200
|
+
resource_id = await _get_user_resource_id(user_id=user_id, db=db)
|
|
201
|
+
if resource_id is None or resource_id != task_group.resource_id:
|
|
202
|
+
raise HTTPException(
|
|
203
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
204
|
+
detail=f"User {user_id} has no access to TaskGroup's Resource.",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if require_active and not task_group.active:
|
|
208
|
+
raise HTTPException(
|
|
209
|
+
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
210
|
+
detail=f"Error: task {task_id} ({task.name}) is not active.",
|
|
211
|
+
)
|
|
212
|
+
|
|
188
213
|
return task
|
|
189
214
|
|
|
190
215
|
|
|
@@ -255,16 +280,19 @@ async def _get_collection_task_group_activity_status_message(
|
|
|
255
280
|
|
|
256
281
|
|
|
257
282
|
async def _verify_non_duplication_user_constraint(
|
|
283
|
+
*,
|
|
258
284
|
db: AsyncSession,
|
|
259
285
|
user_id: int,
|
|
260
286
|
pkg_name: str,
|
|
261
287
|
version: str | None,
|
|
288
|
+
user_resource_id: int,
|
|
262
289
|
):
|
|
263
290
|
stm = (
|
|
264
291
|
select(TaskGroupV2)
|
|
265
292
|
.where(TaskGroupV2.user_id == user_id)
|
|
266
293
|
.where(TaskGroupV2.pkg_name == pkg_name)
|
|
267
294
|
.where(TaskGroupV2.version == version)
|
|
295
|
+
.where(TaskGroupV2.resource_id == user_resource_id)
|
|
268
296
|
)
|
|
269
297
|
res = await db.execute(stm)
|
|
270
298
|
duplicate = res.scalars().all()
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/project.py
RENAMED
|
@@ -15,9 +15,9 @@ from ....models.v2 import ProjectV2
|
|
|
15
15
|
from ....schemas.v2 import ProjectCreateV2
|
|
16
16
|
from ....schemas.v2 import ProjectReadV2
|
|
17
17
|
from ....schemas.v2 import ProjectUpdateV2
|
|
18
|
+
from ...aux.validate_user_profile import validate_user_profile
|
|
18
19
|
from ._aux_functions import _check_project_exists
|
|
19
20
|
from ._aux_functions import _get_project_check_owner
|
|
20
|
-
from ._aux_functions import _get_resource_and_profile_ids
|
|
21
21
|
from ._aux_functions import _get_submitted_jobs_statement
|
|
22
22
|
from fractal_server.app.models import UserOAuth
|
|
23
23
|
from fractal_server.app.routes.auth import current_user_act_ver_prof
|
|
@@ -54,13 +54,17 @@ async def create_project(
|
|
|
54
54
|
Create new project
|
|
55
55
|
"""
|
|
56
56
|
|
|
57
|
+
# Get validated resource and profile
|
|
58
|
+
resource, profile = await validate_user_profile(
|
|
59
|
+
user=user,
|
|
60
|
+
db=db,
|
|
61
|
+
)
|
|
62
|
+
resource_id = resource.id
|
|
63
|
+
|
|
57
64
|
# Check that there is no project with the same user and name
|
|
58
65
|
await _check_project_exists(
|
|
59
66
|
project_name=project.name, user_id=user.id, db=db
|
|
60
67
|
)
|
|
61
|
-
resource_id, _ = await _get_resource_and_profile_ids(
|
|
62
|
-
user_id=user.id, db=db
|
|
63
|
-
)
|
|
64
68
|
|
|
65
69
|
db_project = ProjectV2(**project.model_dump(), resource_id=resource_id)
|
|
66
70
|
db_project.user_list.append(user)
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/submit.py
RENAMED
|
@@ -59,6 +59,9 @@ async def apply_workflow(
|
|
|
59
59
|
) -> JobReadV2 | None:
|
|
60
60
|
# Remove non-submitted V2 jobs from the app state when the list grows
|
|
61
61
|
# beyond a threshold
|
|
62
|
+
# NOTE: this may lead to a race condition on `app.state.jobsV2` if two
|
|
63
|
+
# requests take place at the same time and `clean_app_job_list_v2` is
|
|
64
|
+
# somewhat slow.
|
|
62
65
|
settings = Inject(get_settings)
|
|
63
66
|
if (
|
|
64
67
|
len(request.app.state.jobsV2)
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/app/routes/api/v2/task.py
RENAMED
|
@@ -9,7 +9,8 @@ from sqlmodel import func
|
|
|
9
9
|
from sqlmodel import or_
|
|
10
10
|
from sqlmodel import select
|
|
11
11
|
|
|
12
|
-
from .
|
|
12
|
+
from ...aux.validate_user_profile import validate_user_profile
|
|
13
|
+
from ._aux_functions import _get_user_resource_id
|
|
13
14
|
from ._aux_functions_tasks import _get_task_full_access
|
|
14
15
|
from ._aux_functions_tasks import _get_task_read_access
|
|
15
16
|
from ._aux_functions_tasks import _get_valid_user_group_id
|
|
@@ -46,10 +47,14 @@ async def get_list_task(
|
|
|
46
47
|
"""
|
|
47
48
|
Get list of available tasks
|
|
48
49
|
"""
|
|
50
|
+
|
|
51
|
+
user_resource_id = await _get_user_resource_id(user_id=user.id, db=db)
|
|
52
|
+
|
|
49
53
|
stm = (
|
|
50
54
|
select(TaskV2)
|
|
51
55
|
.join(TaskGroupV2)
|
|
52
56
|
.where(TaskGroupV2.id == TaskV2.taskgroupv2_id)
|
|
57
|
+
.where(TaskGroupV2.resource_id == user_resource_id)
|
|
53
58
|
.where(
|
|
54
59
|
or_(
|
|
55
60
|
TaskGroupV2.user_id == user.id,
|
|
@@ -144,6 +149,13 @@ async def create_task(
|
|
|
144
149
|
Create a new task
|
|
145
150
|
"""
|
|
146
151
|
|
|
152
|
+
# Get validated resource and profile
|
|
153
|
+
resource, profile = await validate_user_profile(
|
|
154
|
+
user=user,
|
|
155
|
+
db=db,
|
|
156
|
+
)
|
|
157
|
+
resource_id = resource.id
|
|
158
|
+
|
|
147
159
|
# Validate query parameters related to user-group ownership
|
|
148
160
|
user_group_id = await _get_valid_user_group_id(
|
|
149
161
|
user_group_id=user_group_id,
|
|
@@ -179,7 +191,11 @@ async def create_task(
|
|
|
179
191
|
db_task = TaskV2(**task.model_dump(exclude_unset=True))
|
|
180
192
|
pkg_name = db_task.name
|
|
181
193
|
await _verify_non_duplication_user_constraint(
|
|
182
|
-
db=db,
|
|
194
|
+
db=db,
|
|
195
|
+
pkg_name=pkg_name,
|
|
196
|
+
user_id=user.id,
|
|
197
|
+
version=db_task.version,
|
|
198
|
+
user_resource_id=resource_id,
|
|
183
199
|
)
|
|
184
200
|
await _verify_non_duplication_group_constraint(
|
|
185
201
|
db=db,
|
|
@@ -187,9 +203,6 @@ async def create_task(
|
|
|
187
203
|
user_group_id=user_group_id,
|
|
188
204
|
version=db_task.version,
|
|
189
205
|
)
|
|
190
|
-
resource_id, _ = await _get_resource_and_profile_ids(
|
|
191
|
-
user_id=user.id, db=db
|
|
192
|
-
)
|
|
193
206
|
db_task_group = TaskGroupV2(
|
|
194
207
|
user_id=user.id,
|
|
195
208
|
user_group_id=user_group_id,
|
|
@@ -25,7 +25,6 @@ from ....schemas.v2 import TaskGroupActivityStatusV2
|
|
|
25
25
|
from ....schemas.v2 import TaskGroupActivityV2Read
|
|
26
26
|
from ....schemas.v2 import TaskGroupCreateV2Strict
|
|
27
27
|
from ...aux.validate_user_profile import validate_user_profile
|
|
28
|
-
from ._aux_functions import _get_resource_and_profile_ids
|
|
29
28
|
from ._aux_functions_task_lifecycle import get_package_version_from_pypi
|
|
30
29
|
from ._aux_functions_tasks import _get_valid_user_group_id
|
|
31
30
|
from ._aux_functions_tasks import _verify_non_duplication_group_constraint
|
|
@@ -173,13 +172,11 @@ async def collect_tasks_pip(
|
|
|
173
172
|
user=user,
|
|
174
173
|
db=db,
|
|
175
174
|
)
|
|
175
|
+
resource_id = resource.id
|
|
176
|
+
|
|
176
177
|
# Get some validated request data
|
|
177
178
|
task_collect = request_data.task_collect
|
|
178
179
|
|
|
179
|
-
resource_id, _ = await _get_resource_and_profile_ids(
|
|
180
|
-
user_id=user.id, db=db
|
|
181
|
-
)
|
|
182
|
-
|
|
183
180
|
# Initialize task-group attributes
|
|
184
181
|
task_group_attrs = dict(
|
|
185
182
|
user_id=user.id,
|
|
@@ -297,6 +294,7 @@ async def collect_tasks_pip(
|
|
|
297
294
|
user_id=user.id,
|
|
298
295
|
pkg_name=task_group_attrs["pkg_name"],
|
|
299
296
|
version=task_group_attrs["version"],
|
|
297
|
+
user_resource_id=resource_id,
|
|
300
298
|
db=db,
|
|
301
299
|
)
|
|
302
300
|
await _verify_non_duplication_group_constraint(
|
|
@@ -10,7 +10,6 @@ from fastapi import status
|
|
|
10
10
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
11
11
|
|
|
12
12
|
from ...aux.validate_user_profile import validate_user_profile
|
|
13
|
-
from ._aux_functions import _get_resource_and_profile_ids
|
|
14
13
|
from ._aux_functions_tasks import _get_valid_user_group_id
|
|
15
14
|
from ._aux_functions_tasks import _verify_non_duplication_group_constraint
|
|
16
15
|
from ._aux_functions_tasks import _verify_non_duplication_user_constraint
|
|
@@ -50,6 +49,7 @@ async def collect_task_custom(
|
|
|
50
49
|
) -> list[TaskReadV2]:
|
|
51
50
|
# Get validated resource and profile
|
|
52
51
|
resource, profile = await validate_user_profile(user=user, db=db)
|
|
52
|
+
resource_id = resource.id
|
|
53
53
|
|
|
54
54
|
# Validate query parameters related to user-group ownership
|
|
55
55
|
user_group_id = await _get_valid_user_group_id(
|
|
@@ -145,10 +145,6 @@ async def collect_task_custom(
|
|
|
145
145
|
package_version=task_collect.version,
|
|
146
146
|
)
|
|
147
147
|
|
|
148
|
-
resource_id, _ = await _get_resource_and_profile_ids(
|
|
149
|
-
user_id=user.id, db=db
|
|
150
|
-
)
|
|
151
|
-
|
|
152
148
|
# Prepare task-group attributes
|
|
153
149
|
task_group_attrs = dict(
|
|
154
150
|
origin=TaskGroupV2OriginEnum.OTHER,
|
|
@@ -165,6 +161,7 @@ async def collect_task_custom(
|
|
|
165
161
|
user_id=user.id,
|
|
166
162
|
pkg_name=task_group_attrs["pkg_name"],
|
|
167
163
|
version=task_group_attrs["version"],
|
|
164
|
+
user_resource_id=resource_id,
|
|
168
165
|
db=db,
|
|
169
166
|
)
|
|
170
167
|
await _verify_non_duplication_group_constraint(
|
|
@@ -10,7 +10,6 @@ from fastapi import Response
|
|
|
10
10
|
from fastapi import status
|
|
11
11
|
from fastapi import UploadFile
|
|
12
12
|
|
|
13
|
-
from ._aux_functions import _get_resource_and_profile_ids
|
|
14
13
|
from fractal_server.app.db import AsyncSession
|
|
15
14
|
from fractal_server.app.db import get_async_db
|
|
16
15
|
from fractal_server.app.models import UserOAuth
|
|
@@ -90,6 +89,7 @@ async def collect_task_pixi(
|
|
|
90
89
|
) -> TaskGroupActivityV2Read:
|
|
91
90
|
# Get validated resource and profile
|
|
92
91
|
resource, profile = await validate_user_profile(user=user, db=db)
|
|
92
|
+
resource_id = resource.id
|
|
93
93
|
|
|
94
94
|
# Check if Pixi is available
|
|
95
95
|
if not resource.tasks_pixi_config:
|
|
@@ -133,10 +133,6 @@ async def collect_task_pixi(
|
|
|
133
133
|
Path(base_tasks_path) / str(user.id) / pkg_name / version
|
|
134
134
|
).as_posix()
|
|
135
135
|
|
|
136
|
-
resource_id, _ = await _get_resource_and_profile_ids(
|
|
137
|
-
user_id=user.id, db=db
|
|
138
|
-
)
|
|
139
|
-
|
|
140
136
|
task_group_attrs = dict(
|
|
141
137
|
user_id=user.id,
|
|
142
138
|
user_group_id=user_group_id,
|
|
@@ -152,6 +148,7 @@ async def collect_task_pixi(
|
|
|
152
148
|
user_id=user.id,
|
|
153
149
|
pkg_name=task_group_attrs["pkg_name"],
|
|
154
150
|
version=task_group_attrs["version"],
|
|
151
|
+
user_resource_id=resource_id,
|
|
155
152
|
db=db,
|
|
156
153
|
)
|
|
157
154
|
await _verify_non_duplication_group_constraint(
|
|
@@ -2,6 +2,7 @@ from fastapi import APIRouter
|
|
|
2
2
|
from httpx_oauth.clients.github import GitHubOAuth2
|
|
3
3
|
from httpx_oauth.clients.google import GoogleOAuth2
|
|
4
4
|
from httpx_oauth.clients.openid import OpenID
|
|
5
|
+
from httpx_oauth.clients.openid import OpenIDConfigurationError
|
|
5
6
|
|
|
6
7
|
from . import cookie_backend
|
|
7
8
|
from . import fastapi_users
|
|
@@ -26,11 +27,21 @@ def _create_client_google(cfg: OAuthSettings) -> GoogleOAuth2:
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
def _create_client_oidc(cfg: OAuthSettings) -> OpenID:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
try:
|
|
31
|
+
open_id = OpenID(
|
|
32
|
+
client_id=cfg.OAUTH_CLIENT_ID.get_secret_value(),
|
|
33
|
+
client_secret=cfg.OAUTH_CLIENT_SECRET.get_secret_value(),
|
|
34
|
+
openid_configuration_endpoint=cfg.OAUTH_OIDC_CONFIG_ENDPOINT.get_secret_value(), # noqa
|
|
35
|
+
)
|
|
36
|
+
except OpenIDConfigurationError as e:
|
|
37
|
+
OAUTH_OIDC_CONFIG_ENDPOINT = (
|
|
38
|
+
cfg.OAUTH_OIDC_CONFIG_ENDPOINT.get_secret_value()
|
|
39
|
+
)
|
|
40
|
+
raise RuntimeError(
|
|
41
|
+
f"Cannot initialize OpenID client. Original error: '{e}'. "
|
|
42
|
+
f"Hint: is {OAUTH_OIDC_CONFIG_ENDPOINT=} reachable?"
|
|
43
|
+
)
|
|
44
|
+
return open_id
|
|
34
45
|
|
|
35
46
|
|
|
36
47
|
def get_oauth_router() -> APIRouter | None:
|
|
@@ -44,7 +55,6 @@ def get_oauth_router() -> APIRouter | None:
|
|
|
44
55
|
return None
|
|
45
56
|
|
|
46
57
|
client_name = oauth_settings.OAUTH_CLIENT_NAME
|
|
47
|
-
|
|
48
58
|
if client_name == "google":
|
|
49
59
|
client = _create_client_google(oauth_settings)
|
|
50
60
|
elif client_name == "github":
|
|
@@ -51,7 +51,7 @@ class Settings(BaseSettings):
|
|
|
51
51
|
Only logs of with this level (or higher) will appear in the console logs.
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
|
-
FRACTAL_API_MAX_JOB_LIST_LENGTH: int =
|
|
54
|
+
FRACTAL_API_MAX_JOB_LIST_LENGTH: int = 25
|
|
55
55
|
"""
|
|
56
56
|
Number of ids that can be stored in the `jobsV2` attribute of
|
|
57
57
|
`app.state`.
|
{fractal_server-2.17.0a6 → fractal_server-2.17.0a8}/fractal_server/migrations/naming_convention.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
NAMING_CONVENTION = {
|
|
2
2
|
"ix": "ix_%(column_0_label)s",
|
|
3
3
|
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
|
4
|
-
"ck": "ck_%(table_name)s_
|
|
4
|
+
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
|
5
5
|
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
|
6
6
|
"pk": "pk_%(table_name)s",
|
|
7
7
|
}
|