fractal-server 2.17.0a3__py3-none-any.whl → 2.17.0a5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/__main__.py +137 -120
  3. fractal_server/app/models/security.py +19 -21
  4. fractal_server/app/models/user_settings.py +1 -0
  5. fractal_server/app/models/v2/task_group.py +1 -0
  6. fractal_server/app/routes/admin/v2/accounting.py +3 -3
  7. fractal_server/app/routes/admin/v2/impersonate.py +2 -2
  8. fractal_server/app/routes/admin/v2/job.py +6 -6
  9. fractal_server/app/routes/admin/v2/profile.py +4 -4
  10. fractal_server/app/routes/admin/v2/project.py +2 -2
  11. fractal_server/app/routes/admin/v2/resource.py +42 -8
  12. fractal_server/app/routes/admin/v2/task.py +2 -2
  13. fractal_server/app/routes/admin/v2/task_group.py +5 -5
  14. fractal_server/app/routes/admin/v2/task_group_lifecycle.py +4 -4
  15. fractal_server/app/routes/api/__init__.py +5 -5
  16. fractal_server/app/routes/api/v2/dataset.py +10 -19
  17. fractal_server/app/routes/api/v2/history.py +8 -8
  18. fractal_server/app/routes/api/v2/images.py +5 -5
  19. fractal_server/app/routes/api/v2/job.py +8 -8
  20. fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
  21. fractal_server/app/routes/api/v2/project.py +6 -6
  22. fractal_server/app/routes/api/v2/status_legacy.py +2 -2
  23. fractal_server/app/routes/api/v2/submit.py +24 -26
  24. fractal_server/app/routes/api/v2/task.py +6 -7
  25. fractal_server/app/routes/api/v2/task_collection.py +4 -3
  26. fractal_server/app/routes/api/v2/task_collection_custom.py +4 -3
  27. fractal_server/app/routes/api/v2/task_collection_pixi.py +2 -2
  28. fractal_server/app/routes/api/v2/task_group.py +6 -6
  29. fractal_server/app/routes/api/v2/task_group_lifecycle.py +4 -4
  30. fractal_server/app/routes/api/v2/task_version_update.py +3 -3
  31. fractal_server/app/routes/api/v2/workflow.py +9 -9
  32. fractal_server/app/routes/api/v2/workflow_import.py +2 -2
  33. fractal_server/app/routes/api/v2/workflowtask.py +5 -5
  34. fractal_server/app/routes/auth/__init__.py +34 -5
  35. fractal_server/app/routes/auth/current_user.py +22 -67
  36. fractal_server/app/routes/auth/group.py +8 -35
  37. fractal_server/app/routes/auth/register.py +2 -2
  38. fractal_server/app/routes/auth/users.py +5 -46
  39. fractal_server/app/schemas/__init__.py +0 -1
  40. fractal_server/app/schemas/user.py +23 -0
  41. fractal_server/app/schemas/v2/task_group.py +1 -0
  42. fractal_server/app/security/__init__.py +134 -46
  43. fractal_server/app/security/signup_email.py +52 -34
  44. fractal_server/config/__init__.py +1 -7
  45. fractal_server/config/_email.py +10 -47
  46. fractal_server/config/_main.py +14 -3
  47. fractal_server/migrations/versions/f65ee53991e3_user_settings_related.py +67 -0
  48. fractal_server/runner/config/_slurm.py +3 -2
  49. fractal_server/runner/executors/slurm_common/base_slurm_runner.py +2 -2
  50. fractal_server/runner/executors/slurm_common/get_slurm_config.py +1 -1
  51. fractal_server/runner/executors/slurm_common/slurm_config.py +7 -13
  52. fractal_server/runner/executors/slurm_ssh/runner.py +1 -1
  53. fractal_server/runner/executors/slurm_sudo/runner.py +1 -1
  54. fractal_server/runner/v2/_slurm_ssh.py +2 -1
  55. fractal_server/runner/v2/_slurm_sudo.py +1 -1
  56. fractal_server/runner/v2/submit_workflow.py +12 -12
  57. {fractal_server-2.17.0a3.dist-info → fractal_server-2.17.0a5.dist-info}/METADATA +1 -2
  58. {fractal_server-2.17.0a3.dist-info → fractal_server-2.17.0a5.dist-info}/RECORD +61 -64
  59. fractal_server/app/routes/aux/validate_user_settings.py +0 -76
  60. fractal_server/app/schemas/user_settings.py +0 -63
  61. fractal_server/app/user_settings.py +0 -32
  62. fractal_server/config/_init_data.py +0 -27
  63. {fractal_server-2.17.0a3.dist-info → fractal_server-2.17.0a5.dist-info}/WHEEL +0 -0
  64. {fractal_server-2.17.0a3.dist-info → fractal_server-2.17.0a5.dist-info}/entry_points.txt +0 -0
  65. {fractal_server-2.17.0a3.dist-info → fractal_server-2.17.0a5.dist-info}/licenses/LICENSE +0 -0
@@ -17,16 +17,14 @@ from ._aux_functions import clean_app_job_list_v2
17
17
  from ._aux_functions_tasks import _check_type_filters_compatibility
18
18
  from fractal_server.app.db import AsyncSession
19
19
  from fractal_server.app.db import get_async_db
20
+ from fractal_server.app.models import Profile
20
21
  from fractal_server.app.models import TaskGroupV2
21
22
  from fractal_server.app.models import UserOAuth
22
23
  from fractal_server.app.models.v2 import JobV2
23
24
  from fractal_server.app.routes.api.v2._aux_functions_tasks import (
24
25
  _get_task_read_access,
25
26
  )
26
- from fractal_server.app.routes.auth import current_active_verified_user
27
- from fractal_server.app.routes.aux.validate_user_settings import (
28
- validate_user_settings,
29
- )
27
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
30
28
  from fractal_server.app.schemas.v2 import JobCreateV2
31
29
  from fractal_server.app.schemas.v2 import JobReadV2
32
30
  from fractal_server.app.schemas.v2 import JobStatusTypeV2
@@ -39,7 +37,7 @@ from fractal_server.runner.set_start_and_last_task_index import (
39
37
  from fractal_server.runner.v2.submit_workflow import submit_workflow
40
38
  from fractal_server.syringe import Inject
41
39
 
42
-
40
+ FRACTAL_CACHE_DIR = ".fractal_cache"
43
41
  router = APIRouter()
44
42
  logger = set_logger(__name__)
45
43
 
@@ -56,7 +54,7 @@ async def apply_workflow(
56
54
  job_create: JobCreateV2,
57
55
  background_tasks: BackgroundTasks,
58
56
  request: Request,
59
- user: UserOAuth = Depends(current_active_verified_user),
57
+ user: UserOAuth = Depends(current_user_act_ver_prof),
60
58
  db: AsyncSession = Depends(get_async_db),
61
59
  ) -> JobReadV2 | None:
62
60
  # Remove non-submitted V2 jobs from the app state when the list grows
@@ -80,6 +78,17 @@ async def apply_workflow(
80
78
  project = output["project"]
81
79
  dataset = output["dataset"]
82
80
 
81
+ # Verify that user's resource matches with project resource
82
+ res = await db.execute(
83
+ select(Profile.resource_id).where(Profile.id == user.profile_id)
84
+ )
85
+ user_resource_id = res.scalar_one()
86
+ if project.resource_id != user_resource_id:
87
+ raise HTTPException(
88
+ status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
89
+ detail="Project resource does not match with user's resource",
90
+ )
91
+
83
92
  workflow = await _get_workflow_check_owner(
84
93
  project_id=project_id, workflow_id=workflow_id, user_id=user.id, db=db
85
94
  )
@@ -129,10 +138,7 @@ async def apply_workflow(
129
138
  user=user,
130
139
  db=db,
131
140
  )
132
- # Validate user settings
133
- user_settings = await validate_user_settings(
134
- user=user, backend=resource.type, db=db
135
- )
141
+
136
142
  # Check that no other job with the same dataset_id is SUBMITTED
137
143
  stm = (
138
144
  select(JobV2)
@@ -150,7 +156,7 @@ async def apply_workflow(
150
156
  )
151
157
 
152
158
  if job_create.slurm_account is not None:
153
- if job_create.slurm_account not in user_settings.slurm_accounts:
159
+ if job_create.slurm_account not in user.slurm_accounts:
154
160
  raise HTTPException(
155
161
  status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
156
162
  detail=(
@@ -159,8 +165,8 @@ async def apply_workflow(
159
165
  ),
160
166
  )
161
167
  else:
162
- if len(user_settings.slurm_accounts) > 0:
163
- job_create.slurm_account = user_settings.slurm_accounts[0]
168
+ if len(user.slurm_accounts) > 0:
169
+ job_create.slurm_account = user.slurm_accounts[0]
164
170
 
165
171
  # User appropriate FractalSSH object
166
172
  if resource.type == ResourceType.SLURM_SSH:
@@ -226,22 +232,17 @@ async def apply_workflow(
226
232
  )
227
233
 
228
234
  # Define user-side job directory
235
+ cache_dir = Path(user.project_dir, FRACTAL_CACHE_DIR)
229
236
  match resource.type:
230
237
  case ResourceType.LOCAL:
231
238
  WORKFLOW_DIR_REMOTE = WORKFLOW_DIR_LOCAL
232
- cache_dir = None
233
239
  case ResourceType.SLURM_SUDO:
234
- cache_dir = (
235
- Path(user_settings.project_dir) / ".fractal_cache"
236
- if user_settings.project_dir is not None
237
- else None
238
- )
239
240
  WORKFLOW_DIR_REMOTE = cache_dir / WORKFLOW_DIR_LOCAL.name
240
241
  case ResourceType.SLURM_SSH:
241
- WORKFLOW_DIR_REMOTE = (
242
- Path(profile.jobs_remote_dir) / WORKFLOW_DIR_LOCAL.name
242
+ WORKFLOW_DIR_REMOTE = Path(
243
+ profile.jobs_remote_dir,
244
+ WORKFLOW_DIR_LOCAL.name,
243
245
  )
244
- cache_dir = None
245
246
 
246
247
  # Update job folders in the db
247
248
  job.working_dir = WORKFLOW_DIR_LOCAL.as_posix()
@@ -249,9 +250,6 @@ async def apply_workflow(
249
250
  await db.merge(job)
250
251
  await db.commit()
251
252
 
252
- # Expunge user settings from db, to use in background task
253
- db.expunge(user_settings)
254
-
255
253
  background_tasks.add_task(
256
254
  submit_workflow,
257
255
  workflow_id=workflow.id,
@@ -259,7 +257,7 @@ async def apply_workflow(
259
257
  job_id=job.id,
260
258
  user_id=user.id,
261
259
  worker_init=job.worker_init,
262
- user_cache_dir=cache_dir.as_posix() if cache_dir else None,
260
+ user_cache_dir=cache_dir.as_posix(),
263
261
  fractal_ssh=fractal_ssh,
264
262
  resource=resource,
265
263
  profile=profile,
@@ -21,8 +21,7 @@ from fractal_server.app.models import LinkUserGroup
21
21
  from fractal_server.app.models import UserOAuth
22
22
  from fractal_server.app.models.v2 import TaskGroupV2
23
23
  from fractal_server.app.models.v2 import TaskV2
24
- from fractal_server.app.routes.auth import current_active_user
25
- from fractal_server.app.routes.auth import current_active_verified_user
24
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
26
25
  from fractal_server.app.schemas.v2 import TaskCreateV2
27
26
  from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
28
27
  from fractal_server.app.schemas.v2 import TaskReadV2
@@ -41,7 +40,7 @@ async def get_list_task(
41
40
  category: str | None = None,
42
41
  modality: str | None = None,
43
42
  author: str | None = None,
44
- user: UserOAuth = Depends(current_active_user),
43
+ user: UserOAuth = Depends(current_user_act_ver_prof),
45
44
  db: AsyncSession = Depends(get_async_db),
46
45
  ) -> list[TaskReadV2]:
47
46
  """
@@ -83,7 +82,7 @@ async def get_list_task(
83
82
  @router.get("/{task_id}/", response_model=TaskReadV2)
84
83
  async def get_task(
85
84
  task_id: int,
86
- user: UserOAuth = Depends(current_active_user),
85
+ user: UserOAuth = Depends(current_user_act_ver_prof),
87
86
  db: AsyncSession = Depends(get_async_db),
88
87
  ) -> TaskReadV2:
89
88
  """
@@ -97,7 +96,7 @@ async def get_task(
97
96
  async def patch_task(
98
97
  task_id: int,
99
98
  task_update: TaskUpdateV2,
100
- user: UserOAuth = Depends(current_active_verified_user),
99
+ user: UserOAuth = Depends(current_user_act_ver_prof),
101
100
  db: AsyncSession = Depends(get_async_db),
102
101
  ) -> TaskReadV2 | None:
103
102
  """
@@ -138,7 +137,7 @@ async def create_task(
138
137
  task: TaskCreateV2,
139
138
  user_group_id: int | None = None,
140
139
  private: bool = False,
141
- user: UserOAuth = Depends(current_active_verified_user),
140
+ user: UserOAuth = Depends(current_user_act_ver_prof),
142
141
  db: AsyncSession = Depends(get_async_db),
143
142
  ) -> TaskReadV2 | None:
144
143
  """
@@ -212,7 +211,7 @@ async def create_task(
212
211
  @router.delete("/{task_id}/", status_code=204)
213
212
  async def delete_task(
214
213
  task_id: int,
215
- user: UserOAuth = Depends(current_active_user),
214
+ user: UserOAuth = Depends(current_user_act_ver_prof),
216
215
  db: AsyncSession = Depends(get_async_db),
217
216
  ) -> Response:
218
217
  """
@@ -33,7 +33,7 @@ from ._aux_functions_tasks import _verify_non_duplication_group_path
33
33
  from ._aux_functions_tasks import _verify_non_duplication_user_constraint
34
34
  from fractal_server.app.models import UserOAuth
35
35
  from fractal_server.app.models.v2 import TaskGroupActivityV2
36
- from fractal_server.app.routes.auth import current_active_verified_user
36
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
37
37
  from fractal_server.app.schemas.v2 import ResourceType
38
38
  from fractal_server.app.schemas.v2 import (
39
39
  TaskGroupActivityActionV2,
@@ -161,7 +161,7 @@ async def collect_tasks_pip(
161
161
  request_data: CollectionRequestData = Depends(parse_request_data),
162
162
  private: bool = False,
163
163
  user_group_id: int | None = None,
164
- user: UserOAuth = Depends(current_active_verified_user),
164
+ user: UserOAuth = Depends(current_user_act_ver_prof),
165
165
  db: AsyncSession = Depends(get_async_db),
166
166
  ) -> TaskGroupActivityV2Read:
167
167
  """
@@ -183,6 +183,7 @@ async def collect_tasks_pip(
183
183
  # Initialize task-group attributes
184
184
  task_group_attrs = dict(
185
185
  user_id=user.id,
186
+ resource_id=resource_id,
186
187
  origin=request_data.origin,
187
188
  )
188
189
 
@@ -320,7 +321,7 @@ async def collect_tasks_pip(
320
321
  )
321
322
 
322
323
  # Create TaskGroupV2 object
323
- task_group = TaskGroupV2(**task_group_attrs, resource_id=resource_id)
324
+ task_group = TaskGroupV2(**task_group_attrs)
324
325
  db.add(task_group)
325
326
  await db.commit()
326
327
  await db.refresh(task_group)
@@ -17,7 +17,7 @@ from ._aux_functions_tasks import _verify_non_duplication_user_constraint
17
17
  from fractal_server.app.db import get_async_db
18
18
  from fractal_server.app.models import UserOAuth
19
19
  from fractal_server.app.models.v2 import TaskGroupV2
20
- from fractal_server.app.routes.auth import current_active_verified_user
20
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
21
21
  from fractal_server.app.schemas.v2 import ResourceType
22
22
  from fractal_server.app.schemas.v2 import TaskCollectCustomV2
23
23
  from fractal_server.app.schemas.v2 import TaskCreateV2
@@ -45,7 +45,7 @@ async def collect_task_custom(
45
45
  task_collect: TaskCollectCustomV2,
46
46
  private: bool = False,
47
47
  user_group_id: int | None = None,
48
- user: UserOAuth = Depends(current_active_verified_user),
48
+ user: UserOAuth = Depends(current_user_act_ver_prof),
49
49
  db: AsyncSession = Depends(get_async_db),
50
50
  ) -> list[TaskReadV2]:
51
51
  # Get validated resource and profile
@@ -156,6 +156,7 @@ async def collect_task_custom(
156
156
  user_id=user.id,
157
157
  user_group_id=user_group_id,
158
158
  version=task_collect.version,
159
+ resource_id=resource_id,
159
160
  )
160
161
  TaskGroupCreateV2(**task_group_attrs)
161
162
 
@@ -173,7 +174,7 @@ async def collect_task_custom(
173
174
  db=db,
174
175
  )
175
176
 
176
- task_group = TaskGroupV2(**task_group_attrs, resource_id=resource_id)
177
+ task_group = TaskGroupV2(**task_group_attrs)
177
178
  db.add(task_group)
178
179
  await db.commit()
179
180
  await db.refresh(task_group)
@@ -28,7 +28,7 @@ from fractal_server.app.routes.api.v2._aux_functions_tasks import (
28
28
  from fractal_server.app.routes.api.v2._aux_functions_tasks import (
29
29
  _verify_non_duplication_user_constraint,
30
30
  )
31
- from fractal_server.app.routes.auth import current_active_verified_user
31
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
32
32
  from fractal_server.app.routes.aux.validate_user_profile import (
33
33
  validate_user_profile,
34
34
  )
@@ -85,7 +85,7 @@ async def collect_task_pixi(
85
85
  pixi_version: NonEmptyStr | None = Form(None),
86
86
  private: bool = False,
87
87
  user_group_id: int | None = None,
88
- user: UserOAuth = Depends(current_active_verified_user),
88
+ user: UserOAuth = Depends(current_user_act_ver_prof),
89
89
  db: AsyncSession = Depends(get_async_db),
90
90
  ) -> TaskGroupActivityV2Read:
91
91
  # Get validated resource and profile
@@ -21,7 +21,7 @@ from fractal_server.app.models import LinkUserGroup
21
21
  from fractal_server.app.models import UserOAuth
22
22
  from fractal_server.app.models.v2 import TaskGroupActivityV2
23
23
  from fractal_server.app.models.v2 import TaskGroupV2
24
- from fractal_server.app.routes.auth import current_active_user
24
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
25
25
  from fractal_server.app.routes.auth._aux_auth import _get_default_usergroup_id
26
26
  from fractal_server.app.routes.auth._aux_auth import (
27
27
  _verify_user_belongs_to_group,
@@ -66,7 +66,7 @@ async def get_task_group_activity_list(
66
66
  status: TaskGroupActivityStatusV2 | None = None,
67
67
  action: TaskGroupActivityActionV2 | None = None,
68
68
  timestamp_started_min: AwareDatetime | None = None,
69
- user: UserOAuth = Depends(current_active_user),
69
+ user: UserOAuth = Depends(current_user_act_ver_prof),
70
70
  db: AsyncSession = Depends(get_async_db),
71
71
  ) -> list[TaskGroupActivityV2Read]:
72
72
  stm = select(TaskGroupActivityV2).where(
@@ -98,7 +98,7 @@ async def get_task_group_activity_list(
98
98
  )
99
99
  async def get_task_group_activity(
100
100
  task_group_activity_id: int,
101
- user: UserOAuth = Depends(current_active_user),
101
+ user: UserOAuth = Depends(current_user_act_ver_prof),
102
102
  db: AsyncSession = Depends(get_async_db),
103
103
  ) -> TaskGroupActivityV2Read:
104
104
  activity = await db.get(TaskGroupActivityV2, task_group_activity_id)
@@ -122,7 +122,7 @@ async def get_task_group_activity(
122
122
 
123
123
  @router.get("/", response_model=list[tuple[str, list[TaskGroupReadV2]]])
124
124
  async def get_task_group_list(
125
- user: UserOAuth = Depends(current_active_user),
125
+ user: UserOAuth = Depends(current_user_act_ver_prof),
126
126
  db: AsyncSession = Depends(get_async_db),
127
127
  only_active: bool = False,
128
128
  only_owner: bool = False,
@@ -182,7 +182,7 @@ async def get_task_group_list(
182
182
  @router.get("/{task_group_id}/", response_model=TaskGroupReadV2)
183
183
  async def get_task_group(
184
184
  task_group_id: int,
185
- user: UserOAuth = Depends(current_active_user),
185
+ user: UserOAuth = Depends(current_user_act_ver_prof),
186
186
  db: AsyncSession = Depends(get_async_db),
187
187
  ) -> TaskGroupReadV2:
188
188
  """
@@ -200,7 +200,7 @@ async def get_task_group(
200
200
  async def patch_task_group(
201
201
  task_group_id: int,
202
202
  task_group_update: TaskGroupUpdateV2,
203
- user: UserOAuth = Depends(current_active_user),
203
+ user: UserOAuth = Depends(current_user_act_ver_prof),
204
204
  db: AsyncSession = Depends(get_async_db),
205
205
  ) -> TaskGroupReadV2:
206
206
  """
@@ -13,7 +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 TaskGroupActivityV2
16
- from fractal_server.app.routes.auth import current_active_user
16
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
17
17
  from fractal_server.app.routes.aux.validate_user_profile import (
18
18
  validate_user_profile,
19
19
  )
@@ -50,7 +50,7 @@ async def deactivate_task_group(
50
50
  task_group_id: int,
51
51
  background_tasks: BackgroundTasks,
52
52
  response: Response,
53
- user: UserOAuth = Depends(current_active_user),
53
+ user: UserOAuth = Depends(current_user_act_ver_prof),
54
54
  db: AsyncSession = Depends(get_async_db),
55
55
  ) -> TaskGroupActivityV2Read:
56
56
  """
@@ -154,7 +154,7 @@ async def reactivate_task_group(
154
154
  task_group_id: int,
155
155
  background_tasks: BackgroundTasks,
156
156
  response: Response,
157
- user: UserOAuth = Depends(current_active_user),
157
+ user: UserOAuth = Depends(current_user_act_ver_prof),
158
158
  db: AsyncSession = Depends(get_async_db),
159
159
  ) -> TaskGroupReadV2:
160
160
  """
@@ -263,7 +263,7 @@ async def delete_task_group(
263
263
  task_group_id: int,
264
264
  background_tasks: BackgroundTasks,
265
265
  response: Response,
266
- user: UserOAuth = Depends(current_active_user),
266
+ user: UserOAuth = Depends(current_user_act_ver_prof),
267
267
  db: AsyncSession = Depends(get_async_db),
268
268
  ) -> TaskGroupActivityV2Read:
269
269
  """
@@ -23,7 +23,7 @@ from ._aux_functions_tasks import _get_task_group_or_404
23
23
  from ._aux_functions_tasks import _get_task_read_access
24
24
  from fractal_server.app.models import UserOAuth
25
25
  from fractal_server.app.models.v2 import TaskGroupV2
26
- from fractal_server.app.routes.auth import current_active_user
26
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
27
27
  from fractal_server.app.schemas.v2 import TaskType
28
28
  from fractal_server.app.schemas.v2 import WorkflowTaskReadV2
29
29
  from fractal_server.app.schemas.v2 import WorkflowTaskReplaceV2
@@ -75,7 +75,7 @@ class TaskVersionRead(BaseModel):
75
75
  async def get_workflow_version_update_candidates(
76
76
  project_id: int,
77
77
  workflow_id: int,
78
- user: UserOAuth = Depends(current_active_user),
78
+ user: UserOAuth = Depends(current_user_act_ver_prof),
79
79
  db: AsyncSession = Depends(get_async_db),
80
80
  ) -> list[list[TaskVersionRead]]:
81
81
  workflow = await _get_workflow_check_owner(
@@ -177,7 +177,7 @@ async def replace_workflowtask(
177
177
  workflow_task_id: int,
178
178
  task_id: int,
179
179
  replace: WorkflowTaskReplaceV2,
180
- user: UserOAuth = Depends(current_active_user),
180
+ user: UserOAuth = Depends(current_user_act_ver_prof),
181
181
  db: AsyncSession = Depends(get_async_db),
182
182
  ) -> WorkflowTaskReadV2:
183
183
  # Get objects from database
@@ -26,7 +26,7 @@ from ._aux_functions import _workflow_has_submitted_job
26
26
  from ._aux_functions_tasks import _add_warnings_to_workflow_tasks
27
27
  from fractal_server.app.models import UserOAuth
28
28
  from fractal_server.app.models.v2 import TaskGroupV2
29
- from fractal_server.app.routes.auth import current_active_user
29
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
30
30
  from fractal_server.images.tools import merge_type_filters
31
31
 
32
32
  router = APIRouter()
@@ -38,7 +38,7 @@ router = APIRouter()
38
38
  )
39
39
  async def get_workflow_list(
40
40
  project_id: int,
41
- user: UserOAuth = Depends(current_active_user),
41
+ user: UserOAuth = Depends(current_user_act_ver_prof),
42
42
  db: AsyncSession = Depends(get_async_db),
43
43
  ) -> list[WorkflowReadV2] | None:
44
44
  """
@@ -65,7 +65,7 @@ async def get_workflow_list(
65
65
  async def create_workflow(
66
66
  project_id: int,
67
67
  workflow: WorkflowCreateV2,
68
- user: UserOAuth = Depends(current_active_user),
68
+ user: UserOAuth = Depends(current_user_act_ver_prof),
69
69
  db: AsyncSession = Depends(get_async_db),
70
70
  ) -> WorkflowReadV2 | None:
71
71
  """
@@ -93,7 +93,7 @@ async def create_workflow(
93
93
  async def read_workflow(
94
94
  project_id: int,
95
95
  workflow_id: int,
96
- user: UserOAuth = Depends(current_active_user),
96
+ user: UserOAuth = Depends(current_user_act_ver_prof),
97
97
  db: AsyncSession = Depends(get_async_db),
98
98
  ) -> WorkflowReadV2WithWarnings | None:
99
99
  """
@@ -127,7 +127,7 @@ async def update_workflow(
127
127
  project_id: int,
128
128
  workflow_id: int,
129
129
  patch: WorkflowUpdateV2,
130
- user: UserOAuth = Depends(current_active_user),
130
+ user: UserOAuth = Depends(current_user_act_ver_prof),
131
131
  db: AsyncSession = Depends(get_async_db),
132
132
  ) -> WorkflowReadV2WithWarnings | None:
133
133
  """
@@ -201,7 +201,7 @@ async def update_workflow(
201
201
  async def delete_workflow(
202
202
  project_id: int,
203
203
  workflow_id: int,
204
- user: UserOAuth = Depends(current_active_user),
204
+ user: UserOAuth = Depends(current_user_act_ver_prof),
205
205
  db: AsyncSession = Depends(get_async_db),
206
206
  ) -> Response:
207
207
  """
@@ -246,7 +246,7 @@ async def delete_workflow(
246
246
  async def export_workflow(
247
247
  project_id: int,
248
248
  workflow_id: int,
249
- user: UserOAuth = Depends(current_active_user),
249
+ user: UserOAuth = Depends(current_user_act_ver_prof),
250
250
  db: AsyncSession = Depends(get_async_db),
251
251
  ) -> WorkflowExportV2 | None:
252
252
  """
@@ -277,7 +277,7 @@ async def export_workflow(
277
277
 
278
278
  @router.get("/workflow/", response_model=list[WorkflowReadV2])
279
279
  async def get_user_workflows(
280
- user: UserOAuth = Depends(current_active_user),
280
+ user: UserOAuth = Depends(current_user_act_ver_prof),
281
281
  db: AsyncSession = Depends(get_async_db),
282
282
  ) -> list[WorkflowReadV2]:
283
283
  """
@@ -303,7 +303,7 @@ class WorkflowTaskTypeFiltersInfo(BaseModel):
303
303
  async def get_workflow_type_filters(
304
304
  project_id: int,
305
305
  workflow_id: int,
306
- user: UserOAuth = Depends(current_active_user),
306
+ user: UserOAuth = Depends(current_user_act_ver_prof),
307
307
  db: AsyncSession = Depends(get_async_db),
308
308
  ) -> list[WorkflowTaskTypeFiltersInfo]:
309
309
  """
@@ -24,7 +24,7 @@ from fractal_server.app.models.v2 import TaskGroupV2
24
24
  from fractal_server.app.routes.api.v2._aux_task_group_disambiguation import (
25
25
  _disambiguate_task_groups,
26
26
  )
27
- from fractal_server.app.routes.auth import current_active_user
27
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
28
28
  from fractal_server.app.routes.auth._aux_auth import _get_default_usergroup_id
29
29
  from fractal_server.app.schemas.v2 import TaskImportV2
30
30
  from fractal_server.logger import set_logger
@@ -205,7 +205,7 @@ async def _get_task_by_taskimport(
205
205
  async def import_workflow(
206
206
  project_id: int,
207
207
  workflow_import: WorkflowImportV2,
208
- user: UserOAuth = Depends(current_active_user),
208
+ user: UserOAuth = Depends(current_user_act_ver_prof),
209
209
  db: AsyncSession = Depends(get_async_db),
210
210
  ) -> WorkflowReadV2WithWarnings:
211
211
  """
@@ -15,7 +15,7 @@ from ._aux_functions import _workflow_insert_task
15
15
  from ._aux_functions_tasks import _check_type_filters_compatibility
16
16
  from ._aux_functions_tasks import _get_task_read_access
17
17
  from fractal_server.app.models import UserOAuth
18
- from fractal_server.app.routes.auth import current_active_user
18
+ from fractal_server.app.routes.auth import current_user_act_ver_prof
19
19
  from fractal_server.app.schemas.v2 import TaskType
20
20
  from fractal_server.app.schemas.v2 import WorkflowTaskCreateV2
21
21
  from fractal_server.app.schemas.v2 import WorkflowTaskReadV2
@@ -34,7 +34,7 @@ async def create_workflowtask(
34
34
  workflow_id: int,
35
35
  task_id: int,
36
36
  wftask: WorkflowTaskCreateV2,
37
- user: UserOAuth = Depends(current_active_user),
37
+ user: UserOAuth = Depends(current_user_act_ver_prof),
38
38
  db: AsyncSession = Depends(get_async_db),
39
39
  ) -> WorkflowTaskReadV2 | None:
40
40
  """
@@ -103,7 +103,7 @@ async def read_workflowtask(
103
103
  project_id: int,
104
104
  workflow_id: int,
105
105
  workflow_task_id: int,
106
- user: UserOAuth = Depends(current_active_user),
106
+ user: UserOAuth = Depends(current_user_act_ver_prof),
107
107
  db: AsyncSession = Depends(get_async_db),
108
108
  ):
109
109
  workflow_task, _ = await _get_workflow_task_check_owner(
@@ -125,7 +125,7 @@ async def update_workflowtask(
125
125
  workflow_id: int,
126
126
  workflow_task_id: int,
127
127
  workflow_task_update: WorkflowTaskUpdateV2,
128
- user: UserOAuth = Depends(current_active_user),
128
+ user: UserOAuth = Depends(current_user_act_ver_prof),
129
129
  db: AsyncSession = Depends(get_async_db),
130
130
  ) -> WorkflowTaskReadV2 | None:
131
131
  """
@@ -210,7 +210,7 @@ async def delete_workflowtask(
210
210
  project_id: int,
211
211
  workflow_id: int,
212
212
  workflow_task_id: int,
213
- user: UserOAuth = Depends(current_active_user),
213
+ user: UserOAuth = Depends(current_user_act_ver_prof),
214
214
  db: AsyncSession = Depends(get_async_db),
215
215
  ) -> Response:
216
216
  """
@@ -1,3 +1,6 @@
1
+ from fastapi import Depends
2
+ from fastapi import HTTPException
3
+ from fastapi import status
1
4
  from fastapi_users import FastAPIUsers
2
5
  from fastapi_users.authentication import AuthenticationBackend
3
6
  from fastapi_users.authentication import BearerTransport
@@ -46,10 +49,36 @@ fastapi_users = FastAPIUsers[UserOAuth, int](
46
49
  get_user_manager,
47
50
  [token_backend, cookie_backend],
48
51
  )
49
- current_active_user = fastapi_users.current_user(active=True)
50
- current_active_verified_user = fastapi_users.current_user(
51
- active=True, verified=True
52
+
53
+ # Current-user dependencies
54
+ current_user_act = fastapi_users.current_user(active=True)
55
+ current_user_act_ver = fastapi_users.current_user(
56
+ active=True,
57
+ verified=True,
52
58
  )
53
- current_active_superuser = fastapi_users.current_user(
54
- active=True, superuser=True
59
+
60
+
61
+ async def current_user_act_ver_prof(
62
+ user: UserOAuth = Depends(current_user_act_ver),
63
+ ) -> UserOAuth:
64
+ """
65
+ Require a active&verified user, with a non-null `profile_id`.
66
+
67
+ Raises 401 if user does not exist or is not active.
68
+ Raises 403 if user is not verified or has null `profile_id`.
69
+ """
70
+ if user.profile_id is None:
71
+ raise HTTPException(
72
+ status_code=status.HTTP_403_FORBIDDEN,
73
+ detail=(
74
+ f"Forbidden access "
75
+ f"({user.is_verified=} {user.profile_id=})."
76
+ ),
77
+ )
78
+ return user
79
+
80
+
81
+ current_superuser_act = fastapi_users.current_user(
82
+ active=True,
83
+ superuser=True,
55
84
  )