fractal-server 2.17.0a5__tar.gz → 2.17.0a7__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.
Files changed (265) hide show
  1. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/PKG-INFO +4 -5
  2. fractal_server-2.17.0a7/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/security.py +7 -1
  4. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/user_settings.py +4 -0
  5. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/profile.py +1 -1
  6. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/project.py +3 -1
  7. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/resource.py +2 -2
  8. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/task_group.py +1 -1
  9. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/profile.py +14 -0
  10. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/resource.py +9 -52
  11. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/task.py +9 -0
  12. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/task_group.py +11 -7
  13. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/__init__.py +9 -0
  14. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/_aux_functions.py +6 -16
  15. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +35 -7
  16. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/project.py +8 -4
  17. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/submit.py +4 -3
  18. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/task.py +18 -5
  19. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/task_collection.py +3 -5
  20. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/task_collection_custom.py +2 -5
  21. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/task_collection_pixi.py +2 -5
  22. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/current_user.py +9 -14
  23. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/oauth.py +16 -6
  24. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/users.py +1 -2
  25. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/user.py +3 -3
  26. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/__init__.py +1 -0
  27. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/task_group.py +4 -0
  28. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/config/__init__.py +6 -1
  29. fractal_server-2.17.0a7/fractal_server/config/_data.py +68 -0
  30. fractal_server-2.17.0a7/fractal_server/config/_main.py +68 -0
  31. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/config/_oauth.py +2 -2
  32. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/main.py +3 -2
  33. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/naming_convention.py +1 -1
  34. fractal_server-2.17.0a5/fractal_server/migrations/versions/a80ac5a352bf_resource_profile.py → fractal_server-2.17.0a7/fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +31 -31
  35. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/pyproject.toml +6 -7
  36. fractal_server-2.17.0a5/fractal_server/__init__.py +0 -1
  37. fractal_server-2.17.0a5/fractal_server/config/_main.py +0 -132
  38. fractal_server-2.17.0a5/fractal_server/data_migrations/2_14_10.py +0 -48
  39. fractal_server-2.17.0a5/fractal_server/migrations/versions/90f6508c6379_drop_useroauth_username.py +0 -36
  40. fractal_server-2.17.0a5/fractal_server/migrations/versions/f65ee53991e3_user_settings_related.py +0 -67
  41. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/LICENSE +0 -0
  42. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/README.md +0 -0
  43. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/__main__.py +0 -0
  44. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/alembic.ini +0 -0
  45. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/__init__.py +0 -0
  46. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/db/__init__.py +0 -0
  47. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/__init__.py +0 -0
  48. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/linkusergroup.py +0 -0
  49. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/linkuserproject.py +0 -0
  50. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/__init__.py +0 -0
  51. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/accounting.py +0 -0
  52. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/dataset.py +0 -0
  53. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/history.py +0 -0
  54. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/job.py +0 -0
  55. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/task.py +0 -0
  56. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/workflow.py +0 -0
  57. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/models/v2/workflowtask.py +0 -0
  58. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/__init__.py +0 -0
  59. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/__init__.py +0 -0
  60. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  61. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/_aux_functions.py +0 -0
  62. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  63. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  64. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/job.py +0 -0
  65. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/project.py +0 -0
  66. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
  67. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  68. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
  69. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
  70. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
  71. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
  72. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/dataset.py +0 -0
  73. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/history.py +0 -0
  74. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/images.py +0 -0
  75. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/job.py +0 -0
  76. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
  77. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
  78. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  79. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
  80. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/task_version_update.py +0 -0
  81. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  82. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  83. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/api/v2/workflowtask.py +0 -0
  84. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/__init__.py +0 -0
  85. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  86. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/group.py +0 -0
  87. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/login.py +0 -0
  88. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/register.py +0 -0
  89. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/auth/router.py +0 -0
  90. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/aux/__init__.py +0 -0
  91. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/aux/_job.py +0 -0
  92. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/aux/_runner.py +0 -0
  93. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/aux/validate_user_profile.py +0 -0
  94. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/routes/pagination.py +0 -0
  95. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/__init__.py +0 -0
  96. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/user_group.py +0 -0
  97. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/accounting.py +0 -0
  98. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/dataset.py +0 -0
  99. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/dumps.py +0 -0
  100. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/history.py +0 -0
  101. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/job.py +0 -0
  102. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/manifest.py +0 -0
  103. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/profile.py +0 -0
  104. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/project.py +0 -0
  105. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/resource.py +0 -0
  106. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  107. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/task.py +0 -0
  108. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  109. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/workflow.py +0 -0
  110. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  111. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/security/__init__.py +0 -0
  112. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/security/signup_email.py +0 -0
  113. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/app/shutdown.py +0 -0
  114. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/config/_database.py +0 -0
  115. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/config/_email.py +0 -0
  116. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/config/_settings_config.py +0 -0
  117. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/data_migrations/README.md +0 -0
  118. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/data_migrations/tools.py +0 -0
  119. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/exceptions.py +0 -0
  120. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/gunicorn_fractal.py +0 -0
  121. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/images/__init__.py +0 -0
  122. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/images/models.py +0 -0
  123. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/images/status_tools.py +0 -0
  124. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/images/tools.py +0 -0
  125. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/logger.py +0 -0
  126. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/env.py +0 -0
  127. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  128. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  129. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +0 -0
  130. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  131. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/1a83a5260664_rename.py +0 -0
  132. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  133. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  134. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  135. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  136. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  137. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  138. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  139. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  140. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  141. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  142. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
  143. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  144. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  145. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  146. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  147. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
  148. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  149. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +0 -0
  150. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  151. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  152. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  153. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  154. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  155. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  156. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  157. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
  158. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +0 -0
  159. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
  160. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  161. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  162. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  163. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  164. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  165. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  166. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  167. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
  168. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  169. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  170. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/py.typed +0 -0
  171. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/__init__.py +0 -0
  172. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/components.py +0 -0
  173. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/config/__init__.py +0 -0
  174. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/config/_local.py +0 -0
  175. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/config/_slurm.py +0 -0
  176. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/config/slurm_mem_to_MB.py +0 -0
  177. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/exceptions.py +0 -0
  178. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/__init__.py +0 -0
  179. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/base_runner.py +0 -0
  180. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/call_command_wrapper.py +0 -0
  181. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/local/__init__.py +0 -0
  182. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/local/get_local_config.py +0 -0
  183. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/local/runner.py +0 -0
  184. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/__init__.py +0 -0
  185. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/_batching.py +0 -0
  186. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/_job_states.py +0 -0
  187. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/base_slurm_runner.py +0 -0
  188. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/get_slurm_config.py +0 -0
  189. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/remote.py +0 -0
  190. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/slurm_config.py +0 -0
  191. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
  192. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_ssh/__init__.py +0 -0
  193. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_ssh/run_subprocess.py +0 -0
  194. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_ssh/runner.py +0 -0
  195. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_ssh/tar_commands.py +0 -0
  196. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_sudo/__init__.py +0 -0
  197. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  198. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/executors/slurm_sudo/runner.py +0 -0
  199. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/filenames.py +0 -0
  200. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/set_start_and_last_task_index.py +0 -0
  201. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/task_files.py +0 -0
  202. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/__init__.py +0 -0
  203. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/_local.py +0 -0
  204. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/_slurm_ssh.py +0 -0
  205. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/_slurm_sudo.py +0 -0
  206. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/db_tools.py +0 -0
  207. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/deduplicate_list.py +0 -0
  208. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/merge_outputs.py +0 -0
  209. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/runner.py +0 -0
  210. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/runner_functions.py +0 -0
  211. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/submit_workflow.py +0 -0
  212. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/v2/task_interface.py +0 -0
  213. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/runner/versions.py +0 -0
  214. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/ssh/__init__.py +0 -0
  215. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/ssh/_fabric.py +0 -0
  216. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/string_tools.py +0 -0
  217. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/syringe.py +0 -0
  218. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/__init__.py +0 -0
  219. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/config/__init__.py +0 -0
  220. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/config/_pixi.py +0 -0
  221. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/config/_python.py +0 -0
  222. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/utils.py +0 -0
  223. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/__init__.py +0 -0
  224. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/__init__.py +0 -0
  225. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/_utils.py +0 -0
  226. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/collect.py +0 -0
  227. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/collect_pixi.py +0 -0
  228. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  229. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
  230. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/delete.py +0 -0
  231. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  232. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/local/reactivate_pixi.py +0 -0
  233. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  234. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py +0 -0
  235. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  236. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  237. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/collect_pixi.py +0 -0
  238. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  239. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
  240. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/delete.py +0 -0
  241. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  242. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +0 -0
  243. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  244. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  245. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  246. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  247. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  248. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  249. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +0 -0
  250. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/pixi_2_install.sh +0 -0
  251. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +0 -0
  252. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/utils_background.py +0 -0
  253. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/utils_database.py +0 -0
  254. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  255. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/utils_pixi.py +0 -0
  256. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  257. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/tasks/v2/utils_templates.py +0 -0
  258. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/types/__init__.py +0 -0
  259. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/types/validators/__init__.py +0 -0
  260. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/types/validators/_common_validators.py +0 -0
  261. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/types/validators/_filter_validators.py +0 -0
  262. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
  263. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/urls.py +0 -0
  264. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/utils.py +0 -0
  265. {fractal_server-2.17.0a5 → fractal_server-2.17.0a7}/fractal_server/zip_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fractal-server
3
- Version: 2.17.0a5
3
+ Version: 2.17.0a7
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE
@@ -13,18 +13,17 @@ Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Dist: alembic (>=1.13.1,<2.0.0)
15
15
  Requires-Dist: fabric (>=3.2.2,<3.3.0)
16
- Requires-Dist: fastapi (>=0.118.0,<0.119.0)
17
- Requires-Dist: fastapi-users[oauth] (>=14,<15)
16
+ Requires-Dist: fastapi (>=0.120.0,<0.121.0)
17
+ Requires-Dist: fastapi-users[oauth] (>=15,<16)
18
18
  Requires-Dist: gunicorn (>=23.0,<24.0)
19
19
  Requires-Dist: packaging (>=25.0.0,<26.0.0)
20
20
  Requires-Dist: psycopg[binary] (>=3.1.0,<4.0.0)
21
21
  Requires-Dist: pydantic (>=2.12.0,<2.13.0)
22
22
  Requires-Dist: pydantic-settings (==2.11.0)
23
- Requires-Dist: python-dotenv (>=1.1.0,<1.2.0)
24
23
  Requires-Dist: sqlalchemy[asyncio] (>=2.0.23,<2.1)
25
24
  Requires-Dist: sqlmodel (==0.0.27)
26
25
  Requires-Dist: tomli_w (>=1.2.0,<1.3.0)
27
- Requires-Dist: uvicorn (>=0.37.0,<0.38.0)
26
+ Requires-Dist: uvicorn (>=0.38.0,<0.39.0)
28
27
  Requires-Dist: uvicorn-worker (==0.4.0)
29
28
  Project-URL: Documentation, https://fractal-analytics-platform.github.io/fractal-server
30
29
  Project-URL: Homepage, https://github.com/fractal-analytics-platform/fractal-server
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.17.0a7"
@@ -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="SET NULL",
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
  """
@@ -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="CASCADE")
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="SET NULL"
20
+ foreign_key="resource.id", default=None, ondelete="RESTRICT"
19
21
  )
20
22
  timestamp_created: datetime = Field(
21
23
  default_factory=get_timestamp,
@@ -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="ck_resource_correct_type",
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="ck_resource_jobs_slurm_python_worker_set",
128
+ name="jobs_slurm_python_worker_set",
129
129
  ),
130
130
  )
@@ -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="SET NULL"
47
+ foreign_key="resource.id", default=None, ondelete="RESTRICT"
48
48
  )
49
49
 
50
50
  origin: str
@@ -10,6 +10,7 @@ from ._aux_functions import _check_profile_name
10
10
  from ._aux_functions import _get_profile_or_404
11
11
  from fractal_server.app.db import AsyncSession
12
12
  from fractal_server.app.db import get_async_db
13
+ from fractal_server.app.models import Profile
13
14
  from fractal_server.app.models import UserOAuth
14
15
  from fractal_server.app.routes.auth import current_superuser_act
15
16
  from fractal_server.app.schemas.v2 import ProfileCreate
@@ -31,6 +32,19 @@ async def get_single_profile(
31
32
  return profile
32
33
 
33
34
 
35
+ @router.get("/", response_model=list[ProfileRead], status_code=200)
36
+ async def get_profile_list(
37
+ superuser: UserOAuth = Depends(current_superuser_act),
38
+ db: AsyncSession = Depends(get_async_db),
39
+ ) -> ProfileRead:
40
+ """
41
+ Query single `Profile`.
42
+ """
43
+ res = await db.execute(select(Profile).order_by(Profile.id))
44
+ profiles = res.scalars().all()
45
+ return profiles
46
+
47
+
34
48
  @router.put("/{profile_id}/", response_model=ProfileRead, status_code=200)
35
49
  async def put_profile(
36
50
  profile_id: int,
@@ -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 sqlmodel import func
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
- # Fail if at least one Profile is associated with the Resource.
156
- res = await db.execute(
157
- select(func.count(Profile.id)).where(
158
- Profile.resource_id == resource_id
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
- f"Cannot delete Resource {resource_id} because it's associated"
183
- f" with {associated_project_count} Projects."
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/",
@@ -10,6 +10,7 @@ from sqlmodel import select
10
10
 
11
11
  from fractal_server.app.db import AsyncSession
12
12
  from fractal_server.app.db import get_async_db
13
+ from fractal_server.app.models import TaskGroupV2
13
14
  from fractal_server.app.models import UserOAuth
14
15
  from fractal_server.app.models.v2 import TaskV2
15
16
  from fractal_server.app.models.v2 import WorkflowTaskV2
@@ -58,6 +59,7 @@ async def query_tasks(
58
59
  category: str | None = None,
59
60
  modality: str | None = None,
60
61
  author: str | None = None,
62
+ resource_id: int | None = None,
61
63
  user: UserOAuth = Depends(current_superuser_act),
62
64
  db: AsyncSession = Depends(get_async_db),
63
65
  ) -> list[TaskV2Info]:
@@ -75,6 +77,7 @@ async def query_tasks(
75
77
  category:
76
78
  modality:
77
79
  author:
80
+ resource_id:
78
81
  """
79
82
 
80
83
  stm = select(TaskV2)
@@ -93,6 +96,12 @@ async def query_tasks(
93
96
  stm = stm.where(func.lower(TaskV2.modality) == modality.lower())
94
97
  if author is not None:
95
98
  stm = stm.where(TaskV2.authors.icontains(author))
99
+ if resource_id is not None:
100
+ stm = (
101
+ stm.join(TaskGroupV2)
102
+ .where(TaskGroupV2.id == TaskV2.taskgroupv2_id)
103
+ .where(TaskGroupV2.resource_id == resource_id)
104
+ )
96
105
 
97
106
  res = await db.execute(stm)
98
107
  task_list = res.scalars().all()
@@ -19,11 +19,12 @@ from fractal_server.app.routes.auth._aux_auth import (
19
19
  from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
20
20
  from fractal_server.app.schemas.v2 import TaskGroupActivityStatusV2
21
21
  from fractal_server.app.schemas.v2 import TaskGroupActivityV2Read
22
- from fractal_server.app.schemas.v2 import TaskGroupReadV2
22
+ from fractal_server.app.schemas.v2 import TaskGroupReadSuperuser
23
23
  from fractal_server.app.schemas.v2 import TaskGroupUpdateV2
24
24
  from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
25
25
  from fractal_server.logger import set_logger
26
26
 
27
+
27
28
  router = APIRouter()
28
29
 
29
30
  logger = set_logger(__name__)
@@ -64,12 +65,12 @@ async def get_task_group_activity_list(
64
65
  return activities
65
66
 
66
67
 
67
- @router.get("/{task_group_id}/", response_model=TaskGroupReadV2)
68
+ @router.get("/{task_group_id}/", response_model=TaskGroupReadSuperuser)
68
69
  async def query_task_group(
69
70
  task_group_id: int,
70
71
  user: UserOAuth = Depends(current_superuser_act),
71
72
  db: AsyncSession = Depends(get_async_db),
72
- ) -> TaskGroupReadV2:
73
+ ) -> TaskGroupReadSuperuser:
73
74
  task_group = await db.get(TaskGroupV2, task_group_id)
74
75
  if task_group is None:
75
76
  raise HTTPException(
@@ -79,7 +80,7 @@ async def query_task_group(
79
80
  return task_group
80
81
 
81
82
 
82
- @router.get("/", response_model=list[TaskGroupReadV2])
83
+ @router.get("/", response_model=list[TaskGroupReadSuperuser])
83
84
  async def query_task_group_list(
84
85
  user_id: int | None = None,
85
86
  user_group_id: int | None = None,
@@ -89,9 +90,10 @@ async def query_task_group_list(
89
90
  origin: TaskGroupV2OriginEnum | None = None,
90
91
  timestamp_last_used_min: AwareDatetime | None = None,
91
92
  timestamp_last_used_max: AwareDatetime | None = None,
93
+ resource_id: int | None = None,
92
94
  user: UserOAuth = Depends(current_superuser_act),
93
95
  db: AsyncSession = Depends(get_async_db),
94
- ) -> list[TaskGroupReadV2]:
96
+ ) -> list[TaskGroupReadSuperuser]:
95
97
  stm = select(TaskGroupV2)
96
98
 
97
99
  if user_group_id is not None and private is True:
@@ -128,19 +130,21 @@ async def query_task_group_list(
128
130
  stm = stm.where(
129
131
  TaskGroupV2.timestamp_last_used <= timestamp_last_used_max
130
132
  )
133
+ if resource_id is not None:
134
+ stm = stm.where(TaskGroupV2.resource_id == resource_id)
131
135
 
132
136
  res = await db.execute(stm)
133
137
  task_groups_list = res.scalars().all()
134
138
  return task_groups_list
135
139
 
136
140
 
137
- @router.patch("/{task_group_id}/", response_model=TaskGroupReadV2)
141
+ @router.patch("/{task_group_id}/", response_model=TaskGroupReadSuperuser)
138
142
  async def patch_task_group(
139
143
  task_group_id: int,
140
144
  task_group_update: TaskGroupUpdateV2,
141
145
  user: UserOAuth = Depends(current_superuser_act),
142
146
  db: AsyncSession = Depends(get_async_db),
143
- ) -> list[TaskGroupReadV2]:
147
+ ) -> list[TaskGroupReadSuperuser]:
144
148
  task_group = await db.get(TaskGroupV2, task_group_id)
145
149
  if task_group is None:
146
150
  raise HTTPException(
@@ -7,6 +7,7 @@ from fastapi import Depends
7
7
  import fractal_server
8
8
  from fractal_server.app.models import UserOAuth
9
9
  from fractal_server.app.routes.auth import current_superuser_act
10
+ from fractal_server.config import get_data_settings
10
11
  from fractal_server.config import get_db_settings
11
12
  from fractal_server.config import get_email_settings
12
13
  from fractal_server.config import get_oauth_settings
@@ -48,6 +49,14 @@ async def view_email_settings(
48
49
  return settings.model_dump()
49
50
 
50
51
 
52
+ @router_api.get("/settings/data/")
53
+ async def view_data_settings(
54
+ user: UserOAuth = Depends(current_superuser_act),
55
+ ):
56
+ settings = Inject(get_data_settings)
57
+ return settings.model_dump()
58
+
59
+
51
60
  @router_api.get("/settings/oauth/")
52
61
  async def view_oauth_settings(
53
62
  user: UserOAuth = Depends(current_superuser_act),
@@ -543,24 +543,14 @@ async def _get_submitted_job_or_none(
543
543
  )
544
544
 
545
545
 
546
- async def _get_resource_and_profile_ids(
547
- *,
548
- user_id: int,
549
- db: AsyncSession,
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
- res = await db.execute(stm)
562
- data = res.one_or_none()
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,8 +84,13 @@ 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
96
  link = res.scalar_one_or_none()
@@ -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
- if require_active:
183
- if not task_group.active:
184
- raise HTTPException(
185
- status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
186
- detail=f"Error: task {task_id} ({task.name}) is not active.",
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()
@@ -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)
@@ -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)
@@ -196,10 +199,8 @@ async def apply_workflow(
196
199
  dataset_id=dataset_id,
197
200
  workflow_id=workflow_id,
198
201
  user_email=user.email,
199
- # The 'filters' field is not supported any more but still exists as a
200
- # database column, therefore we manually exclude it from dumps.
201
202
  dataset_dump=json.loads(
202
- dataset.model_dump_json(exclude={"images", "history", "filters"})
203
+ dataset.model_dump_json(exclude={"images", "history"})
203
204
  ),
204
205
  workflow_dump=json.loads(
205
206
  workflow.model_dump_json(exclude={"task_list"})
@@ -9,7 +9,8 @@ from sqlmodel import func
9
9
  from sqlmodel import or_
10
10
  from sqlmodel import select
11
11
 
12
- from ._aux_functions import _get_resource_and_profile_ids
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, pkg_name=pkg_name, user_id=user.id, version=db_task.version
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(