fractal-server 2.18.0a1__tar.gz → 2.18.0a3__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 (274) hide show
  1. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/PKG-INFO +1 -1
  2. fractal_server-2.18.0a3/fractal_server/__init__.py +1 -0
  3. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/__main__.py +2 -1
  4. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/security.py +7 -5
  5. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/__init__.py +0 -9
  6. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/dataset.py +35 -9
  7. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/submit.py +1 -1
  8. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/workflowtask.py +0 -27
  9. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/current_user.py +0 -63
  10. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/group.py +1 -30
  11. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/router.py +2 -0
  12. fractal_server-2.18.0a3/fractal_server/app/routes/auth/viewer_paths.py +43 -0
  13. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/user.py +29 -12
  14. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/user_group.py +0 -15
  15. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/security/__init__.py +1 -1
  16. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/config/__init__.py +0 -6
  17. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/config/_main.py +5 -0
  18. fractal_server-2.18.0a3/fractal_server/data_migrations/2_18_1.py +29 -0
  19. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/main.py +57 -3
  20. fractal_server-2.18.0a3/fractal_server/migrations/versions/7910eed4cf97_user_project_dirs_and_usergroup_viewer_.py +60 -0
  21. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/_local.py +1 -1
  22. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/_slurm_ssh.py +1 -1
  23. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/_slurm_sudo.py +1 -1
  24. fractal_server-2.18.0a3/fractal_server/tasks/v2/__init__.py +0 -0
  25. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/types/__init__.py +13 -0
  26. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/types/validators/__init__.py +1 -0
  27. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/types/validators/_common_validators.py +10 -0
  28. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/pyproject.toml +2 -2
  29. fractal_server-2.18.0a1/fractal_server/__init__.py +0 -1
  30. fractal_server-2.18.0a1/fractal_server/config/_data.py +0 -79
  31. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/LICENSE +0 -0
  32. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/README.md +0 -0
  33. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/alembic.ini +0 -0
  34. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/__init__.py +0 -0
  35. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/db/__init__.py +0 -0
  36. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/__init__.py +0 -0
  37. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/linkusergroup.py +0 -0
  38. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/linkuserproject.py +0 -0
  39. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/__init__.py +0 -0
  40. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/accounting.py +0 -0
  41. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/dataset.py +0 -0
  42. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/history.py +0 -0
  43. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/job.py +0 -0
  44. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/profile.py +0 -0
  45. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/project.py +0 -0
  46. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/resource.py +0 -0
  47. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/task.py +0 -0
  48. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/task_group.py +0 -0
  49. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/workflow.py +0 -0
  50. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/models/v2/workflowtask.py +0 -0
  51. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/__init__.py +0 -0
  52. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/__init__.py +0 -0
  53. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/__init__.py +0 -0
  54. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/_aux_functions.py +0 -0
  55. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/accounting.py +0 -0
  56. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/impersonate.py +0 -0
  57. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/job.py +0 -0
  58. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/profile.py +0 -0
  59. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/resource.py +0 -0
  60. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/sharing.py +0 -0
  61. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/task.py +0 -0
  62. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/task_group.py +0 -0
  63. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/admin/v2/task_group_lifecycle.py +0 -0
  64. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/__init__.py +0 -0
  65. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/_aux_functions.py +0 -0
  66. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/_aux_functions_history.py +0 -0
  67. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/_aux_functions_sharing.py +0 -0
  68. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +0 -0
  69. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/_aux_functions_task_version_update.py +0 -0
  70. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/_aux_functions_tasks.py +0 -0
  71. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/_aux_task_group_disambiguation.py +0 -0
  72. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/history.py +0 -0
  73. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/images.py +0 -0
  74. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/job.py +0 -0
  75. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/pre_submission_checks.py +0 -0
  76. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/project.py +0 -0
  77. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/sharing.py +0 -0
  78. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/status_legacy.py +0 -0
  79. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/task.py +0 -0
  80. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/task_collection.py +0 -0
  81. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/task_collection_custom.py +0 -0
  82. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/task_collection_pixi.py +0 -0
  83. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/task_group.py +0 -0
  84. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/task_group_lifecycle.py +0 -0
  85. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/task_version_update.py +0 -0
  86. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/workflow.py +0 -0
  87. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/api/v2/workflow_import.py +0 -0
  88. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/__init__.py +0 -0
  89. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/_aux_auth.py +0 -0
  90. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/login.py +0 -0
  91. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/oauth.py +0 -0
  92. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/register.py +0 -0
  93. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/auth/users.py +0 -0
  94. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/aux/__init__.py +0 -0
  95. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/aux/_job.py +0 -0
  96. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/aux/_runner.py +0 -0
  97. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/aux/validate_user_profile.py +0 -0
  98. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/routes/pagination.py +0 -0
  99. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/__init__.py +0 -0
  100. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/__init__.py +0 -0
  101. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/accounting.py +0 -0
  102. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/dataset.py +0 -0
  103. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/dumps.py +0 -0
  104. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/history.py +0 -0
  105. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/job.py +0 -0
  106. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/manifest.py +0 -0
  107. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/profile.py +0 -0
  108. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/project.py +0 -0
  109. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/resource.py +0 -0
  110. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/sharing.py +0 -0
  111. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/status_legacy.py +0 -0
  112. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/task.py +0 -0
  113. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/task_collection.py +0 -0
  114. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/task_group.py +0 -0
  115. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/workflow.py +0 -0
  116. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/schemas/v2/workflowtask.py +0 -0
  117. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/security/signup_email.py +0 -0
  118. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/app/shutdown.py +0 -0
  119. /fractal_server-2.18.0a1/fractal_server/py.typed → /fractal_server-2.18.0a3/fractal_server/config/_data.py +0 -0
  120. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/config/_database.py +0 -0
  121. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/config/_email.py +0 -0
  122. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/config/_oauth.py +0 -0
  123. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/config/_settings_config.py +0 -0
  124. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/data_migrations/README.md +0 -0
  125. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/data_migrations/tools.py +0 -0
  126. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/exceptions.py +0 -0
  127. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/gunicorn_fractal.py +0 -0
  128. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/images/__init__.py +0 -0
  129. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/images/models.py +0 -0
  130. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/images/status_tools.py +0 -0
  131. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/images/tools.py +0 -0
  132. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/logger.py +0 -0
  133. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/env.py +0 -0
  134. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/naming_convention.py +0 -0
  135. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/034a469ec2eb_task_groups.py +0 -0
  136. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +0 -0
  137. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/0f5f85bb2ae7_add_pre_pinned_packages.py +0 -0
  138. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/19eca0dd47a9_user_settings_project_dir.py +0 -0
  139. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/1a83a5260664_rename.py +0 -0
  140. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/1eac13a26c83_drop_v1_tables.py +0 -0
  141. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/316140ff7ee1_remove_usersettings_cache_dir.py +0 -0
  142. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/40d6d6511b20_add_index_to_history_models.py +0 -0
  143. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/45fbb391d7af_make_resource_id_fk_non_nullable.py +0 -0
  144. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/47351f8c7ebc_drop_dataset_filters.py +0 -0
  145. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/49d0856e9569_drop_table.py +0 -0
  146. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py +0 -0
  147. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py +0 -0
  148. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/501961cfcd85_remove_link_between_v1_and_v2_tasks_.py +0 -0
  149. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/50a13d6138fd_initial_schema.py +0 -0
  150. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/5bf02391cfef_v2.py +0 -0
  151. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/70e77f1c38b0_add_applyworkflow_first_task_index_and_.py +0 -0
  152. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/71eefd1dd202_add_slurm_accounts.py +0 -0
  153. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/7673fe18c05d_remove_project_dir_server_default.py +0 -0
  154. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/791ce783d3d8_add_indices.py +0 -0
  155. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/83bc2ad3ffcc_2_17_0.py +0 -0
  156. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/84bf0fffde30_add_dumps_to_applyworkflow.py +0 -0
  157. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/8e8f227a3e36_update_taskv2_post_2_7_0.py +0 -0
  158. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/8f79bd162e35_add_docs_info_and_docs_link_to_task_.py +0 -0
  159. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/94a47ea2d3ff_remove_cache_dir_slurm_user_and_slurm_.py +0 -0
  160. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/969d84257cac_add_historyrun_task_id.py +0 -0
  161. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/97f444d47249_add_applyworkflow_project_dump.py +0 -0
  162. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/981d588fe248_add_executor_error_log.py +0 -0
  163. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/99ea79d9e5d2_add_dataset_history.py +0 -0
  164. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/9c5ae74c9b98_add_user_settings_table.py +0 -0
  165. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/9db60297b8b2_set_ondelete.py +0 -0
  166. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/9fd26a2b0de4_add_workflow_timestamp_created.py +0 -0
  167. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/a7f4d6137b53_add_workflow_dump_to_applyworkflow.py +0 -0
  168. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/af1ef1c83c9b_add_accounting_tables.py +0 -0
  169. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/af8673379a5c_drop_old_filter_columns.py +0 -0
  170. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +0 -0
  171. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/b3ffb095f973_json_to_jsonb.py +0 -0
  172. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/bc0e8b3327a7_project_sharing.py +0 -0
  173. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/c90a7c76e996_job_id_in_history_run.py +0 -0
  174. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/caba9fb1ea5e_drop_useroauth_user_settings_id.py +0 -0
  175. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/d256a7379ab8_taskgroup_activity_and_venv_info_to_.py +0 -0
  176. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/d4fe3708d309_make_applyworkflow_workflow_dump_non_.py +0 -0
  177. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/da2cb2ac4255_user_group_viewer_paths.py +0 -0
  178. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/db09233ad13a_split_filters_and_keep_old_columns.py +0 -0
  179. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/e0e717ae2f26_delete_linkuserproject_ondelete_project.py +0 -0
  180. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/e75cac726012_make_applyworkflow_start_timestamp_not_.py +0 -0
  181. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/e81103413827_add_job_type_filters.py +0 -0
  182. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/efa89c30e0a4_add_project_timestamp_created.py +0 -0
  183. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/f37aceb45062_make_historyunit_logfile_required.py +0 -0
  184. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/f384e1c0cf5d_drop_task_default_args_columns.py +0 -0
  185. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/migrations/versions/fbce16ff4e47_new_history_items.py +0 -0
  186. /fractal_server-2.18.0a1/fractal_server/runner/__init__.py → /fractal_server-2.18.0a3/fractal_server/py.typed +0 -0
  187. {fractal_server-2.18.0a1/fractal_server/runner/executors → fractal_server-2.18.0a3/fractal_server/runner}/__init__.py +0 -0
  188. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/components.py +0 -0
  189. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/config/__init__.py +0 -0
  190. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/config/_local.py +0 -0
  191. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/config/_slurm.py +0 -0
  192. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/config/slurm_mem_to_MB.py +0 -0
  193. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/exceptions.py +0 -0
  194. {fractal_server-2.18.0a1/fractal_server/runner/executors/local → fractal_server-2.18.0a3/fractal_server/runner/executors}/__init__.py +0 -0
  195. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/base_runner.py +0 -0
  196. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/call_command_wrapper.py +0 -0
  197. {fractal_server-2.18.0a1/fractal_server/runner/executors/slurm_common → fractal_server-2.18.0a3/fractal_server/runner/executors/local}/__init__.py +0 -0
  198. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/local/get_local_config.py +0 -0
  199. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/local/runner.py +0 -0
  200. {fractal_server-2.18.0a1/fractal_server/runner/executors/slurm_ssh → fractal_server-2.18.0a3/fractal_server/runner/executors/slurm_common}/__init__.py +0 -0
  201. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_common/_batching.py +0 -0
  202. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_common/_job_states.py +0 -0
  203. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_common/base_slurm_runner.py +0 -0
  204. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_common/get_slurm_config.py +0 -0
  205. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_common/remote.py +0 -0
  206. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_common/slurm_config.py +0 -0
  207. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_common/slurm_job_task_models.py +0 -0
  208. {fractal_server-2.18.0a1/fractal_server/runner/executors/slurm_sudo → fractal_server-2.18.0a3/fractal_server/runner/executors/slurm_ssh}/__init__.py +0 -0
  209. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_ssh/run_subprocess.py +0 -0
  210. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_ssh/runner.py +0 -0
  211. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_ssh/tar_commands.py +0 -0
  212. {fractal_server-2.18.0a1/fractal_server/runner/v2 → fractal_server-2.18.0a3/fractal_server/runner/executors/slurm_sudo}/__init__.py +0 -0
  213. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_sudo/_subprocess_run_as_user.py +0 -0
  214. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/executors/slurm_sudo/runner.py +0 -0
  215. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/filenames.py +0 -0
  216. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/set_start_and_last_task_index.py +0 -0
  217. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/task_files.py +0 -0
  218. {fractal_server-2.18.0a1/fractal_server/tasks → fractal_server-2.18.0a3/fractal_server/runner}/v2/__init__.py +0 -0
  219. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/db_tools.py +0 -0
  220. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/deduplicate_list.py +0 -0
  221. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/merge_outputs.py +0 -0
  222. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/runner.py +0 -0
  223. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/runner_functions.py +0 -0
  224. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/submit_workflow.py +0 -0
  225. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/v2/task_interface.py +0 -0
  226. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/runner/versions.py +0 -0
  227. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/ssh/__init__.py +0 -0
  228. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/ssh/_fabric.py +0 -0
  229. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/string_tools.py +0 -0
  230. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/syringe.py +0 -0
  231. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/__init__.py +0 -0
  232. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/config/__init__.py +0 -0
  233. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/config/_pixi.py +0 -0
  234. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/config/_python.py +0 -0
  235. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/utils.py +0 -0
  236. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/__init__.py +0 -0
  237. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/_utils.py +0 -0
  238. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/collect.py +0 -0
  239. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/collect_pixi.py +0 -0
  240. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/deactivate.py +0 -0
  241. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/deactivate_pixi.py +0 -0
  242. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/delete.py +0 -0
  243. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/reactivate.py +0 -0
  244. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/local/reactivate_pixi.py +0 -0
  245. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/__init__.py +0 -0
  246. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/_pixi_slurm_ssh.py +0 -0
  247. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/_utils.py +0 -0
  248. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/collect.py +0 -0
  249. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/collect_pixi.py +0 -0
  250. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/deactivate.py +0 -0
  251. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/deactivate_pixi.py +0 -0
  252. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/delete.py +0 -0
  253. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/reactivate.py +0 -0
  254. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/ssh/reactivate_pixi.py +0 -0
  255. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/1_create_venv.sh +0 -0
  256. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/2_pip_install.sh +0 -0
  257. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/3_pip_freeze.sh +0 -0
  258. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/4_pip_show.sh +0 -0
  259. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/5_get_venv_size_and_file_number.sh +0 -0
  260. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/6_pip_install_from_freeze.sh +0 -0
  261. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/pixi_1_extract.sh +0 -0
  262. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/pixi_2_install.sh +0 -0
  263. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/templates/pixi_3_post_install.sh +0 -0
  264. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/utils_background.py +0 -0
  265. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/utils_database.py +0 -0
  266. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/utils_package_names.py +0 -0
  267. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/utils_pixi.py +0 -0
  268. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/utils_python_interpreter.py +0 -0
  269. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/tasks/v2/utils_templates.py +0 -0
  270. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/types/validators/_filter_validators.py +0 -0
  271. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/types/validators/_workflow_task_arguments_validators.py +0 -0
  272. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/urls.py +0 -0
  273. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/fractal_server/utils.py +0 -0
  274. {fractal_server-2.18.0a1 → fractal_server-2.18.0a3}/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.18.0a1
3
+ Version: 2.18.0a3
4
4
  Summary: Backend component of the Fractal analytics platform
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE
@@ -0,0 +1 @@
1
+ __VERSION__ = "2.18.0a3"
@@ -167,7 +167,8 @@ def init_db_data(
167
167
  "`--admin-pwd` and `--admin-project-dir`. Exit."
168
168
  )
169
169
  sys.exit(1)
170
- if admin_password and admin_email:
170
+
171
+ if admin_email:
171
172
  asyncio.run(
172
173
  _create_first_user(
173
174
  email=admin_email,
@@ -6,7 +6,6 @@ from pydantic import EmailStr
6
6
  from sqlalchemy import Column
7
7
  from sqlalchemy import String
8
8
  from sqlalchemy.dialects.postgresql import ARRAY
9
- from sqlalchemy.dialects.postgresql import JSONB
10
9
  from sqlalchemy.types import DateTime
11
10
  from sqlmodel import Field
12
11
  from sqlmodel import Relationship
@@ -113,7 +112,13 @@ class UserOAuth(SQLModel, table=True):
113
112
  ondelete="RESTRICT",
114
113
  )
115
114
 
116
- project_dir: str
115
+ # TODO-2.18.1: drop `project_dir`
116
+ project_dir: str | None = Field(default=None, nullable=True)
117
+ # TODO-2.18.1: `project_dirs: list[str] = Field(min_length=1)`
118
+ project_dirs: list[str] = Field(
119
+ sa_column=Column(ARRAY(String), nullable=False, server_default="{}"),
120
+ )
121
+
117
122
  slurm_accounts: list[str] = Field(
118
123
  sa_column=Column(ARRAY(String), server_default="{}"),
119
124
  )
@@ -135,6 +140,3 @@ class UserGroup(SQLModel, table=True):
135
140
  default_factory=get_timestamp,
136
141
  sa_column=Column(DateTime(timezone=True), nullable=False),
137
142
  )
138
- viewer_paths: list[str] = Field(
139
- sa_column=Column(JSONB, server_default="[]", nullable=False)
140
- )
@@ -8,7 +8,6 @@ from fastapi import Depends
8
8
  import fractal_server
9
9
  from fractal_server.app.models import UserOAuth
10
10
  from fractal_server.app.routes.auth import current_superuser_act
11
- from fractal_server.config import get_data_settings
12
11
  from fractal_server.config import get_db_settings
13
12
  from fractal_server.config import get_email_settings
14
13
  from fractal_server.config import get_oauth_settings
@@ -50,14 +49,6 @@ async def view_email_settings(
50
49
  return settings.model_dump()
51
50
 
52
51
 
53
- @router_api.get("/settings/data/")
54
- async def view_data_settings(
55
- user: UserOAuth = Depends(current_superuser_act),
56
- ):
57
- settings = Inject(get_data_settings)
58
- return settings.model_dump()
59
-
60
-
61
52
  @router_api.get("/settings/oauth/")
62
53
  async def view_oauth_settings(
63
54
  user: UserOAuth = Depends(current_superuser_act),
@@ -1,3 +1,5 @@
1
+ from pathlib import Path
2
+
1
3
  from fastapi import APIRouter
2
4
  from fastapi import Depends
3
5
  from fastapi import HTTPException
@@ -58,7 +60,7 @@ async def create_dataset(
58
60
  await db.commit()
59
61
  await db.refresh(db_dataset)
60
62
  path = (
61
- f"{user.project_dir}/fractal/"
63
+ f"{user.project_dirs[0]}/fractal/"
62
64
  f"{project_id}_{sanitize_string(project.name)}/"
63
65
  f"{db_dataset.id}_{sanitize_string(db_dataset.name)}"
64
66
  )
@@ -69,6 +71,18 @@ async def create_dataset(
69
71
  await db.commit()
70
72
  await db.refresh(db_dataset)
71
73
  else:
74
+ if not any(
75
+ Path(dataset.zarr_dir).is_relative_to(project_dir)
76
+ for project_dir in user.project_dirs
77
+ ):
78
+ raise HTTPException(
79
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
80
+ detail=(
81
+ "Dataset zarr_dir is not relative to any of the user "
82
+ "project directories."
83
+ ),
84
+ )
85
+
72
86
  db_dataset = DatasetV2(project_id=project_id, **dataset.model_dump())
73
87
  db.add(db_dataset)
74
88
  await db.commit()
@@ -154,14 +168,26 @@ async def update_dataset(
154
168
  )
155
169
  db_dataset = output["dataset"]
156
170
 
157
- if (dataset_update.zarr_dir is not None) and (len(db_dataset.images) != 0):
158
- raise HTTPException(
159
- status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
160
- detail=(
161
- "Cannot modify `zarr_dir` because the dataset has a non-empty "
162
- "image list."
163
- ),
164
- )
171
+ if dataset_update.zarr_dir is not None:
172
+ if db_dataset.images:
173
+ raise HTTPException(
174
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
175
+ detail=(
176
+ "Cannot modify `zarr_dir` because the dataset has a "
177
+ "non-empty image list."
178
+ ),
179
+ )
180
+ if not any(
181
+ Path(dataset_update.zarr_dir).is_relative_to(project_dir)
182
+ for project_dir in user.project_dirs
183
+ ):
184
+ raise HTTPException(
185
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
186
+ detail=(
187
+ "Dataset zarr_dir is not relative to any of the user "
188
+ "project directories."
189
+ ),
190
+ )
165
191
 
166
192
  for key, value in dataset_update.model_dump(exclude_unset=True).items():
167
193
  setattr(db_dataset, key, value)
@@ -238,7 +238,7 @@ async def apply_workflow(
238
238
  )
239
239
 
240
240
  # Define user-side job directory
241
- cache_dir = Path(user.project_dir, FRACTAL_CACHE_DIR)
241
+ cache_dir = Path(user.project_dirs[0], FRACTAL_CACHE_DIR)
242
242
  match resource.type:
243
243
  case ResourceType.LOCAL:
244
244
  WORKFLOW_DIR_REMOTE = WORKFLOW_DIR_LOCAL
@@ -5,12 +5,10 @@ from fastapi import Depends
5
5
  from fastapi import HTTPException
6
6
  from fastapi import Response
7
7
  from fastapi import status
8
- from sqlmodel import select
9
8
 
10
9
  from fractal_server.app.db import AsyncSession
11
10
  from fractal_server.app.db import get_async_db
12
11
  from fractal_server.app.models import UserOAuth
13
- from fractal_server.app.models.linkuserproject import LinkUserProjectV2
14
12
  from fractal_server.app.routes.auth import current_user_act_ver_prof
15
13
  from fractal_server.app.schemas.v2 import TaskType
16
14
  from fractal_server.app.schemas.v2 import WorkflowTaskCreateV2
@@ -53,31 +51,6 @@ async def create_workflowtask(
53
51
  db=db,
54
52
  )
55
53
 
56
- res = await db.execute(
57
- select(UserOAuth.id)
58
- .join(LinkUserProjectV2, LinkUserProjectV2.user_id == UserOAuth.id)
59
- .where(LinkUserProjectV2.project_id == project_id)
60
- .where(LinkUserProjectV2.is_owner.is_(True))
61
- )
62
- project_owner_id = res.scalar_one()
63
- if project_owner_id != user.id:
64
- try:
65
- await _get_task_read_access(
66
- task_id=task_id,
67
- user_id=project_owner_id,
68
- db=db,
69
- require_active=True,
70
- )
71
- except HTTPException as e:
72
- raise (
73
- HTTPException(
74
- status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
75
- detail="The task must be accessible to the project owner.",
76
- )
77
- if e.status_code == 403
78
- else e
79
- )
80
-
81
54
  task = await _get_task_read_access(
82
55
  task_id=task_id, user_id=user.id, db=db, require_active=True
83
56
  )
@@ -2,21 +2,16 @@
2
2
  Definition of `/auth/current-user/` endpoints
3
3
  """
4
4
 
5
- import os
6
-
7
5
  from fastapi import APIRouter
8
6
  from fastapi import Depends
9
7
  from sqlalchemy.ext.asyncio import AsyncSession
10
8
  from sqlmodel import select
11
9
 
12
10
  from fractal_server.app.db import get_async_db
13
- from fractal_server.app.models import LinkUserGroup
14
11
  from fractal_server.app.models import Profile
15
12
  from fractal_server.app.models import Resource
16
- from fractal_server.app.models import UserGroup
17
13
  from fractal_server.app.models import UserOAuth
18
14
  from fractal_server.app.routes.auth import current_user_act
19
- from fractal_server.app.routes.auth import current_user_act_ver
20
15
  from fractal_server.app.routes.auth._aux_auth import (
21
16
  _get_single_user_with_groups,
22
17
  )
@@ -26,9 +21,6 @@ from fractal_server.app.schemas.user import UserUpdate
26
21
  from fractal_server.app.schemas.user import UserUpdateStrict
27
22
  from fractal_server.app.security import UserManager
28
23
  from fractal_server.app.security import get_user_manager
29
- from fractal_server.config import DataAuthScheme
30
- from fractal_server.config import get_data_settings
31
- from fractal_server.syringe import Inject
32
24
 
33
25
  router_current_user = APIRouter()
34
26
 
@@ -106,58 +98,3 @@ async def get_current_user_profile_info(
106
98
  )
107
99
 
108
100
  return response_data
109
-
110
-
111
- @router_current_user.get(
112
- "/current-user/allowed-viewer-paths/", response_model=list[str]
113
- )
114
- async def get_current_user_allowed_viewer_paths(
115
- current_user: UserOAuth = Depends(current_user_act_ver),
116
- db: AsyncSession = Depends(get_async_db),
117
- ) -> list[str]:
118
- """
119
- Returns the allowed viewer paths for current user, according to the
120
- selected FRACTAL_DATA_AUTH_SCHEME
121
- """
122
-
123
- data_settings = Inject(get_data_settings)
124
-
125
- authorized_paths = []
126
-
127
- if data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.NONE:
128
- return authorized_paths
129
-
130
- # Append `project_dir` to the list of authorized paths
131
- authorized_paths.append(current_user.project_dir)
132
-
133
- # If auth scheme is "users-folders" and `slurm_user` is set,
134
- # build and append the user folder
135
- if (
136
- data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.USERS_FOLDERS
137
- and current_user.profile_id is not None
138
- ):
139
- profile = await db.get(Profile, current_user.profile_id)
140
- if profile is not None and profile.username is not None:
141
- base_folder = data_settings.FRACTAL_DATA_BASE_FOLDER
142
- user_folder = os.path.join(base_folder, profile.username)
143
- authorized_paths.append(user_folder)
144
-
145
- if data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.VIEWER_PATHS:
146
- # Returns the union of `viewer_paths` for all user's groups
147
- cmd = (
148
- select(UserGroup.viewer_paths)
149
- .join(LinkUserGroup, LinkUserGroup.group_id == UserGroup.id)
150
- .where(LinkUserGroup.user_id == current_user.id)
151
- )
152
- res = await db.execute(cmd)
153
- viewer_paths_nested = res.scalars().all()
154
-
155
- # Flatten a nested object and make its elements unique
156
- all_viewer_paths_set = {
157
- path
158
- for _viewer_paths in viewer_paths_nested
159
- for path in _viewer_paths
160
- }
161
- authorized_paths.extend(all_viewer_paths_set)
162
-
163
- return authorized_paths
@@ -16,7 +16,6 @@ from fractal_server.app.models import UserGroup
16
16
  from fractal_server.app.models import UserOAuth
17
17
  from fractal_server.app.schemas.user_group import UserGroupCreate
18
18
  from fractal_server.app.schemas.user_group import UserGroupRead
19
- from fractal_server.app.schemas.user_group import UserGroupUpdate
20
19
  from fractal_server.config import get_settings
21
20
  from fractal_server.logger import set_logger
22
21
  from fractal_server.syringe import Inject
@@ -101,41 +100,13 @@ async def create_single_group(
101
100
  )
102
101
 
103
102
  # Create and return new group
104
- new_group = UserGroup(
105
- name=group_create.name, viewer_paths=group_create.viewer_paths
106
- )
103
+ new_group = UserGroup(name=group_create.name)
107
104
  db.add(new_group)
108
105
  await db.commit()
109
106
 
110
107
  return dict(new_group.model_dump(), user_ids=[])
111
108
 
112
109
 
113
- @router_group.patch(
114
- "/group/{group_id}/",
115
- response_model=UserGroupRead,
116
- status_code=status.HTTP_200_OK,
117
- )
118
- async def update_single_group(
119
- group_id: int,
120
- group_update: UserGroupUpdate,
121
- user: UserOAuth = Depends(current_superuser_act),
122
- db: AsyncSession = Depends(get_async_db),
123
- ) -> UserGroupRead:
124
- group = await _usergroup_or_404(group_id, db)
125
-
126
- # Patch `viewer_paths`
127
- if group_update.viewer_paths is not None:
128
- group.viewer_paths = group_update.viewer_paths
129
- db.add(group)
130
- await db.commit()
131
-
132
- updated_group = await _get_single_usergroup_with_user_ids(
133
- group_id=group_id, db=db
134
- )
135
-
136
- return updated_group
137
-
138
-
139
110
  @router_group.delete("/group/{group_id}/", status_code=204)
140
111
  async def delete_single_group(
141
112
  group_id: int,
@@ -6,6 +6,7 @@ from .login import router_login
6
6
  from .oauth import get_oauth_router
7
7
  from .register import router_register
8
8
  from .users import router_users
9
+ from .viewer_paths import router_viewer_paths
9
10
 
10
11
  router_auth = APIRouter()
11
12
 
@@ -14,6 +15,7 @@ router_auth.include_router(router_current_user)
14
15
  router_auth.include_router(router_login)
15
16
  router_auth.include_router(router_users)
16
17
  router_auth.include_router(router_group)
18
+ router_auth.include_router(router_viewer_paths)
17
19
  router_oauth = get_oauth_router()
18
20
  if router_oauth is not None:
19
21
  router_auth.include_router(router_oauth)
@@ -0,0 +1,43 @@
1
+ from fastapi import APIRouter
2
+ from fastapi import Depends
3
+ from sqlalchemy.ext.asyncio import AsyncSession
4
+ from sqlmodel import select
5
+
6
+ from fractal_server.app.db import get_async_db
7
+ from fractal_server.app.models import UserOAuth
8
+ from fractal_server.app.models.linkuserproject import LinkUserProjectV2
9
+ from fractal_server.app.models.v2.dataset import DatasetV2
10
+ from fractal_server.app.models.v2.project import ProjectV2
11
+ from fractal_server.app.routes.auth import current_user_act_ver
12
+
13
+ router_viewer_paths = APIRouter()
14
+
15
+
16
+ @router_viewer_paths.get(
17
+ "/current-user/allowed-viewer-paths/", response_model=list[str]
18
+ )
19
+ async def get_current_user_allowed_viewer_paths(
20
+ include_shared_projects: bool = True,
21
+ current_user: UserOAuth = Depends(current_user_act_ver),
22
+ db: AsyncSession = Depends(get_async_db),
23
+ ) -> list[str]:
24
+ """
25
+ Returns the allowed viewer paths for current user.
26
+ """
27
+ authorized_paths = current_user.project_dirs.copy()
28
+
29
+ if include_shared_projects:
30
+ res = await db.execute(
31
+ select(DatasetV2.zarr_dir)
32
+ .join(ProjectV2, ProjectV2.id == DatasetV2.project_id)
33
+ .join(
34
+ LinkUserProjectV2, LinkUserProjectV2.project_id == ProjectV2.id
35
+ )
36
+ .where(LinkUserProjectV2.user_id == current_user.id)
37
+ .where(LinkUserProjectV2.is_owner.is_(False))
38
+ )
39
+ authorized_paths.extend(res.unique().scalars().all())
40
+ # Note that `project_dirs` and the `db.execute` result may have some
41
+ # common elements, and then this list may have non-unique items.
42
+
43
+ return authorized_paths
@@ -8,12 +8,18 @@ from pydantic import EmailStr
8
8
  from pydantic import Field
9
9
 
10
10
  from fractal_server.string_tools import validate_cmd
11
- from fractal_server.types import AbsolutePathStr
11
+ from fractal_server.types import ListUniqueAbsolutePathStr
12
12
  from fractal_server.types import ListUniqueNonEmptyString
13
13
  from fractal_server.types import ListUniqueNonNegativeInt
14
14
  from fractal_server.types import NonEmptyStr
15
15
 
16
16
 
17
+ def _validate_cmd_list(value: list[str]) -> list[str]:
18
+ for v in value:
19
+ validate_cmd(v)
20
+ return value
21
+
22
+
17
23
  class OAuthAccountRead(BaseModel):
18
24
  """
19
25
  Schema for storing essential `OAuthAccount` information within
@@ -38,20 +44,17 @@ class UserRead(schemas.BaseUser[int]):
38
44
  group_ids_names:
39
45
  oauth_accounts:
40
46
  profile_id:
47
+ project_dirs:
48
+ slurm_accounts:
41
49
  """
42
50
 
43
51
  group_ids_names: list[tuple[int, str]] | None = None
44
52
  oauth_accounts: list[OAuthAccountRead]
45
53
  profile_id: int | None = None
46
- project_dir: str
54
+ project_dirs: list[str]
47
55
  slurm_accounts: list[str]
48
56
 
49
57
 
50
- def _validate_cmd(value: str) -> str:
51
- validate_cmd(value)
52
- return value
53
-
54
-
55
58
  class UserUpdate(schemas.BaseUserUpdate):
56
59
  """
57
60
  Schema for `User` update.
@@ -63,7 +66,7 @@ class UserUpdate(schemas.BaseUserUpdate):
63
66
  is_superuser:
64
67
  is_verified:
65
68
  profile_id:
66
- project_dir:
69
+ project_dirs:
67
70
  slurm_accounts:
68
71
  """
69
72
 
@@ -74,9 +77,9 @@ class UserUpdate(schemas.BaseUserUpdate):
74
77
  is_superuser: bool = None
75
78
  is_verified: bool = None
76
79
  profile_id: int | None = None
77
- project_dir: Annotated[AbsolutePathStr, AfterValidator(_validate_cmd)] = (
78
- None
79
- )
80
+ project_dirs: Annotated[
81
+ ListUniqueAbsolutePathStr, AfterValidator(_validate_cmd_list)
82
+ ] = None
80
83
  slurm_accounts: ListUniqueNonEmptyString = None
81
84
 
82
85
 
@@ -98,10 +101,14 @@ class UserCreate(schemas.BaseUserCreate):
98
101
 
99
102
  Attributes:
100
103
  profile_id:
104
+ project_dirs:
105
+ slurm_accounts:
101
106
  """
102
107
 
103
108
  profile_id: int | None = None
104
- project_dir: Annotated[AbsolutePathStr, AfterValidator(_validate_cmd)]
109
+ project_dirs: Annotated[
110
+ ListUniqueAbsolutePathStr, AfterValidator(_validate_cmd_list)
111
+ ] = Field(min_length=1)
105
112
  slurm_accounts: list[str] = Field(default_factory=list)
106
113
 
107
114
 
@@ -109,6 +116,8 @@ class UserUpdateGroups(BaseModel):
109
116
  """
110
117
  Schema for `POST /auth/users/{user_id}/set-groups/`
111
118
 
119
+ Attributes:
120
+ group_ids:
112
121
  """
113
122
 
114
123
  model_config = ConfigDict(extra="forbid")
@@ -117,6 +126,14 @@ class UserUpdateGroups(BaseModel):
117
126
 
118
127
 
119
128
  class UserProfileInfo(BaseModel):
129
+ """
130
+ Attributes:
131
+ has_profile:
132
+ resource_name:
133
+ profile_name:
134
+ username:
135
+ """
136
+
120
137
  has_profile: bool
121
138
  resource_name: str | None = None
122
139
  profile_name: str | None = None
@@ -2,16 +2,13 @@ from datetime import datetime
2
2
 
3
3
  from pydantic import BaseModel
4
4
  from pydantic import ConfigDict
5
- from pydantic import Field
6
5
  from pydantic import field_serializer
7
6
  from pydantic.types import AwareDatetime
8
7
 
9
- from fractal_server.types import ListUniqueAbsolutePathStr
10
8
  from fractal_server.types import NonEmptyStr
11
9
 
12
10
  __all__ = (
13
11
  "UserGroupRead",
14
- "UserGroupUpdate",
15
12
  "UserGroupCreate",
16
13
  )
17
14
 
@@ -34,7 +31,6 @@ class UserGroupRead(BaseModel):
34
31
  name: str
35
32
  timestamp_created: AwareDatetime
36
33
  user_ids: list[int] | None = None
37
- viewer_paths: list[str]
38
34
 
39
35
  @field_serializer("timestamp_created")
40
36
  def serialize_datetime(v: datetime) -> str:
@@ -52,14 +48,3 @@ class UserGroupCreate(BaseModel):
52
48
  model_config = ConfigDict(extra="forbid")
53
49
 
54
50
  name: NonEmptyStr
55
- viewer_paths: ListUniqueAbsolutePathStr = Field(default_factory=list)
56
-
57
-
58
- class UserGroupUpdate(BaseModel):
59
- """
60
- Schema for `UserGroup` update
61
- """
62
-
63
- model_config = ConfigDict(extra="forbid")
64
-
65
- viewer_paths: ListUniqueAbsolutePathStr = None
@@ -425,7 +425,7 @@ async def _create_first_user(
425
425
  kwargs = dict(
426
426
  email=email,
427
427
  password=password,
428
- project_dir=project_dir,
428
+ project_dirs=[project_dir],
429
429
  profile_id=profile_id,
430
430
  is_superuser=is_superuser,
431
431
  is_verified=is_verified,
@@ -1,5 +1,3 @@
1
- from ._data import DataAuthScheme # noqa F401
2
- from ._data import DataSettings
3
1
  from ._database import DatabaseSettings
4
2
  from ._email import EmailSettings
5
3
  from ._email import PublicEmailSettings # noqa F401
@@ -21,7 +19,3 @@ def get_email_settings(email_settings=EmailSettings()) -> EmailSettings:
21
19
 
22
20
  def get_oauth_settings(oauth_settings=OAuthSettings()) -> OAuthSettings:
23
21
  return oauth_settings
24
-
25
-
26
- def get_data_settings(data_settings=DataSettings()) -> DataSettings:
27
- return data_settings
@@ -41,6 +41,10 @@ class Settings(BaseSettings):
41
41
  user group (e.g. it cannot be deleted, and new users are
42
42
  automatically added to it). If set to `None` (the default value),
43
43
  then user groups are all equivalent, independently on their name.
44
+ FRACTAL_LONG_REQUEST_TIME:
45
+ Time limit beyond which the execution of an API request is
46
+ considered *slow* and an appropriate warning is logged by the
47
+ middleware.
44
48
  """
45
49
 
46
50
  model_config = SettingsConfigDict(**SETTINGS_CONFIG_DICT)
@@ -57,3 +61,4 @@ class Settings(BaseSettings):
57
61
  FRACTAL_GRACEFUL_SHUTDOWN_TIME: float = 30.0
58
62
  FRACTAL_HELP_URL: HttpUrl | None = None
59
63
  FRACTAL_DEFAULT_GROUP_NAME: Literal["All"] | None = None
64
+ FRACTAL_LONG_REQUEST_TIME: float = 30.0
@@ -0,0 +1,29 @@
1
+ import logging
2
+ import sys
3
+
4
+ from sqlalchemy.orm.attributes import flag_modified
5
+ from sqlmodel import select
6
+
7
+ from fractal_server.app.db import get_sync_db
8
+ from fractal_server.app.models import UserOAuth
9
+
10
+ logging.basicConfig(level=logging.INFO)
11
+
12
+
13
+ def fix_db():
14
+ logging.info("START - fix db")
15
+
16
+ with next(get_sync_db()) as db:
17
+ res = db.execute(select(UserOAuth).order_by(UserOAuth.email))
18
+ user_list = res.scalars().unique().all()
19
+
20
+ for user in user_list:
21
+ logging.info(f"Now handling user {user.email}.")
22
+ if user.project_dirs != []:
23
+ sys.exit(f"Non empty `project_dirs` for User[{user.id}]")
24
+ user.project_dirs.append(user.project_dir)
25
+ flag_modified(user, "project_dirs")
26
+
27
+ db.commit()
28
+
29
+ logging.info("END - fix db")