fractal-server 2.18.6__py3-none-any.whl → 2.19.0__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 (57) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/app/models/security.py +16 -0
  3. fractal_server/app/models/v2/dataset.py +0 -4
  4. fractal_server/app/models/v2/job.py +4 -0
  5. fractal_server/app/models/v2/task.py +0 -1
  6. fractal_server/app/models/v2/task_group.py +4 -0
  7. fractal_server/app/models/v2/workflow.py +2 -0
  8. fractal_server/app/models/v2/workflowtask.py +3 -0
  9. fractal_server/app/routes/admin/v2/sharing.py +47 -0
  10. fractal_server/app/routes/admin/v2/task.py +0 -5
  11. fractal_server/app/routes/admin/v2/task_group_lifecycle.py +6 -0
  12. fractal_server/app/routes/api/__init__.py +4 -52
  13. fractal_server/app/routes/api/alive.py +13 -0
  14. fractal_server/app/routes/api/settings.py +44 -0
  15. fractal_server/app/routes/api/v2/__init__.py +0 -2
  16. fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +1 -20
  17. fractal_server/app/routes/api/v2/dataset.py +9 -8
  18. fractal_server/app/routes/api/v2/history.py +8 -8
  19. fractal_server/app/routes/api/v2/images.py +6 -5
  20. fractal_server/app/routes/api/v2/job.py +10 -9
  21. fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
  22. fractal_server/app/routes/api/v2/project.py +7 -6
  23. fractal_server/app/routes/api/v2/sharing.py +17 -9
  24. fractal_server/app/routes/api/v2/submit.py +5 -3
  25. fractal_server/app/routes/api/v2/task.py +7 -6
  26. fractal_server/app/routes/api/v2/task_collection.py +4 -2
  27. fractal_server/app/routes/api/v2/task_collection_custom.py +2 -2
  28. fractal_server/app/routes/api/v2/task_collection_pixi.py +4 -2
  29. fractal_server/app/routes/api/v2/task_group.py +9 -30
  30. fractal_server/app/routes/api/v2/task_group_lifecycle.py +10 -4
  31. fractal_server/app/routes/api/v2/task_version_update.py +4 -3
  32. fractal_server/app/routes/api/v2/workflow.py +10 -9
  33. fractal_server/app/routes/api/v2/workflow_import.py +14 -45
  34. fractal_server/app/routes/api/v2/workflowtask.py +7 -11
  35. fractal_server/app/routes/auth/__init__.py +18 -1
  36. fractal_server/app/routes/auth/current_user.py +8 -0
  37. fractal_server/app/routes/auth/users.py +11 -0
  38. fractal_server/app/routes/aux/_versions.py +42 -0
  39. fractal_server/app/schemas/user.py +7 -0
  40. fractal_server/app/schemas/v2/__init__.py +0 -1
  41. fractal_server/app/schemas/v2/dumps.py +0 -1
  42. fractal_server/app/schemas/v2/task.py +0 -5
  43. fractal_server/app/schemas/v2/workflow.py +2 -0
  44. fractal_server/app/schemas/v2/workflowtask.py +6 -2
  45. fractal_server/app/security/__init__.py +8 -3
  46. fractal_server/migrations/versions/18a26fcdea5d_drop_dataset_history.py +41 -0
  47. fractal_server/migrations/versions/1bf8785755f9_add_description_to_workflow_and_.py +53 -0
  48. fractal_server/migrations/versions/5fb08bf05b14_drop_taskv2_source.py +36 -0
  49. fractal_server/migrations/versions/cfd13f7954e7_add_fractal_server_version_to_jobv2_and_.py +52 -0
  50. fractal_server/migrations/versions/e53dc51fdf93_add_useroauth_is_guest.py +36 -0
  51. fractal_server/runner/v2/submit_workflow.py +0 -2
  52. {fractal_server-2.18.6.dist-info → fractal_server-2.19.0.dist-info}/METADATA +2 -2
  53. {fractal_server-2.18.6.dist-info → fractal_server-2.19.0.dist-info}/RECORD +56 -49
  54. fractal_server/app/routes/api/v2/status_legacy.py +0 -156
  55. {fractal_server-2.18.6.dist-info → fractal_server-2.19.0.dist-info}/WHEEL +0 -0
  56. {fractal_server-2.18.6.dist-info → fractal_server-2.19.0.dist-info}/entry_points.txt +0 -0
  57. {fractal_server-2.18.6.dist-info → fractal_server-2.19.0.dist-info}/licenses/LICENSE +0 -0
@@ -15,7 +15,8 @@ from fractal_server.app.db import get_async_db
15
15
  from fractal_server.app.models import UserOAuth
16
16
  from fractal_server.app.models.v2 import JobV2
17
17
  from fractal_server.app.models.v2 import LinkUserProjectV2
18
- from fractal_server.app.routes.auth import current_user_act_ver_prof
18
+ from fractal_server.app.routes.auth import get_api_guest
19
+ from fractal_server.app.routes.auth import get_api_user
19
20
  from fractal_server.app.routes.aux._job import _write_shutdown_file
20
21
  from fractal_server.app.routes.aux._runner import _check_shutdown_is_supported
21
22
  from fractal_server.app.schemas.v2 import JobRead
@@ -41,12 +42,12 @@ router = APIRouter()
41
42
 
42
43
  @router.get("/job/", response_model=list[JobRead])
43
44
  async def get_user_jobs(
44
- user: UserOAuth = Depends(current_user_act_ver_prof),
45
+ user: UserOAuth = Depends(get_api_guest),
45
46
  log: bool = True,
46
47
  db: AsyncSession = Depends(get_async_db),
47
48
  ) -> list[JobRead]:
48
49
  """
49
- Returns all the jobs of the current user
50
+ Returns all the jobs from projects linked to the current user
50
51
  """
51
52
  stm = (
52
53
  select(JobV2)
@@ -73,7 +74,7 @@ async def get_user_jobs(
73
74
  async def get_workflow_jobs(
74
75
  project_id: int,
75
76
  workflow_id: int,
76
- user: UserOAuth = Depends(current_user_act_ver_prof),
77
+ user: UserOAuth = Depends(get_api_guest),
77
78
  db: AsyncSession = Depends(get_async_db),
78
79
  ) -> list[JobRead] | None:
79
80
  """
@@ -100,7 +101,7 @@ async def get_latest_job(
100
101
  project_id: int,
101
102
  workflow_id: int,
102
103
  dataset_id: int,
103
- user: UserOAuth = Depends(current_user_act_ver_prof),
104
+ user: UserOAuth = Depends(get_api_guest),
104
105
  db: AsyncSession = Depends(get_async_db),
105
106
  ) -> JobRead:
106
107
  await _get_workflow_check_access(
@@ -136,7 +137,7 @@ async def read_job(
136
137
  project_id: int,
137
138
  job_id: int,
138
139
  show_tmp_logs: bool = False,
139
- user: UserOAuth = Depends(current_user_act_ver_prof),
140
+ user: UserOAuth = Depends(get_api_guest),
140
141
  db: AsyncSession = Depends(get_async_db),
141
142
  ) -> JobRead | None:
142
143
  """
@@ -169,7 +170,7 @@ async def read_job(
169
170
  async def download_job_logs(
170
171
  project_id: int,
171
172
  job_id: int,
172
- user: UserOAuth = Depends(current_user_act_ver_prof),
173
+ user: UserOAuth = Depends(get_api_guest),
173
174
  db: AsyncSession = Depends(get_async_db),
174
175
  ) -> StreamingResponse:
175
176
  """
@@ -200,7 +201,7 @@ async def download_job_logs(
200
201
  )
201
202
  async def get_job_list(
202
203
  project_id: int,
203
- user: UserOAuth = Depends(current_user_act_ver_prof),
204
+ user: UserOAuth = Depends(get_api_guest),
204
205
  log: bool = True,
205
206
  db: AsyncSession = Depends(get_async_db),
206
207
  ) -> list[JobRead] | None:
@@ -234,7 +235,7 @@ async def get_job_list(
234
235
  async def stop_job(
235
236
  project_id: int,
236
237
  job_id: int,
237
- user: UserOAuth = Depends(current_user_act_ver_prof),
238
+ user: UserOAuth = Depends(get_api_user),
238
239
  db: AsyncSession = Depends(get_async_db),
239
240
  ) -> Response:
240
241
  """
@@ -8,7 +8,7 @@ from pydantic import Field
8
8
  from fractal_server.app.db import AsyncSession
9
9
  from fractal_server.app.db import get_async_db
10
10
  from fractal_server.app.models import UserOAuth
11
- from fractal_server.app.routes.auth import current_user_act_ver_prof
11
+ from fractal_server.app.routes.auth import get_api_guest
12
12
  from fractal_server.app.schemas.v2 import HistoryUnitStatus
13
13
  from fractal_server.app.schemas.v2 import TaskType
14
14
  from fractal_server.app.schemas.v2.sharing import ProjectPermissions
@@ -34,7 +34,7 @@ async def verify_unique_types(
34
34
  dataset_id: int,
35
35
  workflowtask_id: int,
36
36
  query: ImageQuery | None = None,
37
- user: UserOAuth = Depends(current_user_act_ver_prof),
37
+ user: UserOAuth = Depends(get_api_guest),
38
38
  db: AsyncSession = Depends(get_async_db),
39
39
  ) -> list[str]:
40
40
  # Get dataset
@@ -99,7 +99,7 @@ async def check_non_processed_images(
99
99
  workflow_id: int,
100
100
  workflowtask_id: int,
101
101
  filters: NonProcessedImagesPayload,
102
- user: UserOAuth = Depends(current_user_act_ver_prof),
102
+ user: UserOAuth = Depends(get_api_guest),
103
103
  db: AsyncSession = Depends(get_async_db),
104
104
  ) -> JSONResponse:
105
105
  db_workflow_task, db_workflow = await _get_workflow_task_check_access(
@@ -11,7 +11,8 @@ from fractal_server.app.models import UserOAuth
11
11
  from fractal_server.app.models.v2 import JobV2
12
12
  from fractal_server.app.models.v2 import LinkUserProjectV2
13
13
  from fractal_server.app.models.v2 import ProjectV2
14
- from fractal_server.app.routes.auth import current_user_act_ver_prof
14
+ from fractal_server.app.routes.auth import get_api_guest
15
+ from fractal_server.app.routes.auth import get_api_user
15
16
  from fractal_server.app.routes.aux.validate_user_profile import (
16
17
  validate_user_profile,
17
18
  )
@@ -32,7 +33,7 @@ router = APIRouter()
32
33
  @router.get("/project/", response_model=list[ProjectRead])
33
34
  async def get_list_project(
34
35
  is_owner: bool = True,
35
- user: UserOAuth = Depends(current_user_act_ver_prof),
36
+ user: UserOAuth = Depends(get_api_guest),
36
37
  db: AsyncSession = Depends(get_async_db),
37
38
  ) -> list[ProjectV2]:
38
39
  """
@@ -53,7 +54,7 @@ async def get_list_project(
53
54
  @router.post("/project/", response_model=ProjectRead, status_code=201)
54
55
  async def create_project(
55
56
  project: ProjectCreate,
56
- user: UserOAuth = Depends(current_user_act_ver_prof),
57
+ user: UserOAuth = Depends(get_api_user),
57
58
  db: AsyncSession = Depends(get_async_db),
58
59
  ) -> ProjectRead | None:
59
60
  """
@@ -94,7 +95,7 @@ async def create_project(
94
95
  @router.get("/project/{project_id}/", response_model=ProjectRead)
95
96
  async def read_project(
96
97
  project_id: int,
97
- user: UserOAuth = Depends(current_user_act_ver_prof),
98
+ user: UserOAuth = Depends(get_api_guest),
98
99
  db: AsyncSession = Depends(get_async_db),
99
100
  ) -> ProjectRead | None:
100
101
  """
@@ -113,7 +114,7 @@ async def read_project(
113
114
  async def update_project(
114
115
  project_id: int,
115
116
  project_update: ProjectUpdate,
116
- user: UserOAuth = Depends(current_user_act_ver_prof),
117
+ user: UserOAuth = Depends(get_api_user),
117
118
  db: AsyncSession = Depends(get_async_db),
118
119
  ):
119
120
  project = await _get_project_check_access(
@@ -140,7 +141,7 @@ async def update_project(
140
141
  @router.delete("/project/{project_id}/", status_code=204)
141
142
  async def delete_project(
142
143
  project_id: int,
143
- user: UserOAuth = Depends(current_user_act_ver_prof),
144
+ user: UserOAuth = Depends(get_api_user),
144
145
  db: AsyncSession = Depends(get_async_db),
145
146
  ) -> Response:
146
147
  """
@@ -11,7 +11,8 @@ from fractal_server.app.db import get_async_db
11
11
  from fractal_server.app.models import UserOAuth
12
12
  from fractal_server.app.models.v2 import LinkUserProjectV2
13
13
  from fractal_server.app.models.v2 import ProjectV2
14
- from fractal_server.app.routes.auth import current_user_act_ver_prof
14
+ from fractal_server.app.routes.auth import get_api_guest
15
+ from fractal_server.app.routes.auth import get_api_user
15
16
  from fractal_server.app.schemas.v2 import ProjectAccessRead
16
17
  from fractal_server.app.schemas.v2 import ProjectGuestCreate
17
18
  from fractal_server.app.schemas.v2 import ProjectGuestRead
@@ -33,7 +34,7 @@ router = APIRouter()
33
34
  )
34
35
  async def get_project_guests(
35
36
  project_id: int,
36
- owner: UserOAuth = Depends(current_user_act_ver_prof),
37
+ owner: UserOAuth = Depends(get_api_guest),
37
38
  db: AsyncSession = Depends(get_async_db),
38
39
  ) -> list[ProjectGuestRead]:
39
40
  """
@@ -68,7 +69,7 @@ async def invite_guest(
68
69
  project_id: int,
69
70
  email: EmailStr,
70
71
  project_invitation: ProjectGuestCreate,
71
- owner: UserOAuth = Depends(current_user_act_ver_prof),
72
+ owner: UserOAuth = Depends(get_api_user),
72
73
  db: AsyncSession = Depends(get_async_db),
73
74
  ) -> Response:
74
75
  """
@@ -103,7 +104,7 @@ async def patch_guest(
103
104
  project_id: int,
104
105
  email: EmailStr,
105
106
  update: ProjectGuestUpdate,
106
- owner: UserOAuth = Depends(current_user_act_ver_prof),
107
+ owner: UserOAuth = Depends(get_api_user),
107
108
  db: AsyncSession = Depends(get_async_db),
108
109
  ) -> Response:
109
110
  """
@@ -137,7 +138,7 @@ async def patch_guest(
137
138
  async def revoke_guest_access(
138
139
  project_id: int,
139
140
  email: EmailStr,
140
- owner: UserOAuth = Depends(current_user_act_ver_prof),
141
+ owner: UserOAuth = Depends(get_api_user),
141
142
  db: AsyncSession = Depends(get_async_db),
142
143
  ) -> Response:
143
144
  """
@@ -171,13 +172,20 @@ async def revoke_guest_access(
171
172
  response_model=list[ProjectInvitationRead],
172
173
  )
173
174
  async def get_pending_invitations(
174
- user: UserOAuth = Depends(current_user_act_ver_prof),
175
+ user: UserOAuth = Depends(get_api_guest),
175
176
  db: AsyncSession = Depends(get_async_db),
176
177
  ) -> list[ProjectInvitationRead]:
177
178
  """
178
179
  See your current invitations.
179
180
  """
180
181
 
182
+ if user.is_guest:
183
+ # The user's attribute `is_guest` is used to identify guest accounts,
184
+ # i.e. accounts with read only permissions on the API.
185
+ # This is a different concept from a project guest, which is a regular
186
+ # account with which a project has been shared.
187
+ return []
188
+
181
189
  res = await db.execute(
182
190
  select(
183
191
  ProjectV2.id,
@@ -225,7 +233,7 @@ async def get_pending_invitations(
225
233
  )
226
234
  async def get_access_info(
227
235
  project_id: int,
228
- user: UserOAuth = Depends(current_user_act_ver_prof),
236
+ user: UserOAuth = Depends(get_api_guest),
229
237
  db: AsyncSession = Depends(get_async_db),
230
238
  ) -> ProjectAccessRead:
231
239
  """
@@ -272,7 +280,7 @@ async def get_access_info(
272
280
  @router.post("/project/{project_id}/access/accept/", status_code=200)
273
281
  async def accept_project_invitation(
274
282
  project_id: int,
275
- user: UserOAuth = Depends(current_user_act_ver_prof),
283
+ user: UserOAuth = Depends(get_api_user),
276
284
  db: AsyncSession = Depends(get_async_db),
277
285
  ) -> Response:
278
286
  """
@@ -290,7 +298,7 @@ async def accept_project_invitation(
290
298
  @router.delete("/project/{project_id}/access/", status_code=204)
291
299
  async def leave_project(
292
300
  project_id: int,
293
- user: UserOAuth = Depends(current_user_act_ver_prof),
301
+ user: UserOAuth = Depends(get_api_user),
294
302
  db: AsyncSession = Depends(get_async_db),
295
303
  ) -> Response:
296
304
  """
@@ -11,6 +11,7 @@ from fastapi import status
11
11
  from sqlmodel import select
12
12
  from sqlmodel import update
13
13
 
14
+ from fractal_server import __VERSION__
14
15
  from fractal_server.app.db import AsyncSession
15
16
  from fractal_server.app.db import get_async_db
16
17
  from fractal_server.app.models import Profile
@@ -20,7 +21,7 @@ from fractal_server.app.models.v2 import JobV2
20
21
  from fractal_server.app.routes.api.v2._aux_functions_tasks import (
21
22
  _get_task_read_access,
22
23
  )
23
- from fractal_server.app.routes.auth import current_user_act_ver_prof
24
+ from fractal_server.app.routes.auth import get_api_user
24
25
  from fractal_server.app.routes.aux.validate_user_profile import (
25
26
  validate_user_profile,
26
27
  )
@@ -59,7 +60,7 @@ async def submit_job(
59
60
  job_create: JobCreate,
60
61
  background_tasks: BackgroundTasks,
61
62
  request: Request,
62
- user: UserOAuth = Depends(current_user_act_ver_prof),
63
+ user: UserOAuth = Depends(get_api_user),
63
64
  db: AsyncSession = Depends(get_async_db),
64
65
  ) -> JobRead | None:
65
66
  # Remove non-submitted Jobs from the app state when the list grows
@@ -216,11 +217,12 @@ async def submit_job(
216
217
  dataset.model_dump_json(exclude={"images", "history"})
217
218
  ),
218
219
  workflow_dump=json.loads(
219
- workflow.model_dump_json(exclude={"task_list"})
220
+ workflow.model_dump_json(exclude={"task_list", "description"})
220
221
  ),
221
222
  project_dump=json.loads(
222
223
  project.model_dump_json(exclude={"resource_id"})
223
224
  ),
225
+ fractal_server_version=__VERSION__,
224
226
  **job_create.model_dump(),
225
227
  )
226
228
 
@@ -24,7 +24,8 @@ from fractal_server.app.models import LinkUserGroup
24
24
  from fractal_server.app.models import UserOAuth
25
25
  from fractal_server.app.models.v2 import TaskGroupV2
26
26
  from fractal_server.app.models.v2 import TaskV2
27
- from fractal_server.app.routes.auth import current_user_act_ver_prof
27
+ from fractal_server.app.routes.auth import get_api_guest
28
+ from fractal_server.app.routes.auth import get_api_user
28
29
  from fractal_server.app.schemas.v2 import TaskCreate
29
30
  from fractal_server.app.schemas.v2 import TaskGroupOriginEnum
30
31
  from fractal_server.app.schemas.v2 import TaskRead
@@ -43,7 +44,7 @@ async def get_list_task(
43
44
  category: str | None = None,
44
45
  modality: str | None = None,
45
46
  author: str | None = None,
46
- user: UserOAuth = Depends(current_user_act_ver_prof),
47
+ user: UserOAuth = Depends(get_api_guest),
47
48
  db: AsyncSession = Depends(get_async_db),
48
49
  ) -> list[TaskRead]:
49
50
  """
@@ -88,7 +89,7 @@ async def get_list_task(
88
89
  @router.get("/{task_id}/", response_model=TaskRead)
89
90
  async def get_task(
90
91
  task_id: int,
91
- user: UserOAuth = Depends(current_user_act_ver_prof),
92
+ user: UserOAuth = Depends(get_api_guest),
92
93
  db: AsyncSession = Depends(get_async_db),
93
94
  ) -> TaskRead:
94
95
  """
@@ -102,7 +103,7 @@ async def get_task(
102
103
  async def patch_task(
103
104
  task_id: int,
104
105
  task_update: TaskUpdate,
105
- user: UserOAuth = Depends(current_user_act_ver_prof),
106
+ user: UserOAuth = Depends(get_api_user),
106
107
  db: AsyncSession = Depends(get_async_db),
107
108
  ) -> TaskRead | None:
108
109
  """
@@ -140,7 +141,7 @@ async def create_task(
140
141
  task: TaskCreate,
141
142
  user_group_id: int | None = None,
142
143
  private: bool = False,
143
- user: UserOAuth = Depends(current_user_act_ver_prof),
144
+ user: UserOAuth = Depends(get_api_user),
144
145
  db: AsyncSession = Depends(get_async_db),
145
146
  ) -> TaskRead | None:
146
147
  """
@@ -221,7 +222,7 @@ async def create_task(
221
222
  @router.delete("/{task_id}/", status_code=204)
222
223
  async def delete_task(
223
224
  task_id: int,
224
- user: UserOAuth = Depends(current_user_act_ver_prof),
225
+ user: UserOAuth = Depends(get_api_user),
225
226
  db: AsyncSession = Depends(get_async_db),
226
227
  ) -> Response:
227
228
  """
@@ -14,12 +14,13 @@ from pydantic import BaseModel
14
14
  from pydantic import ValidationError
15
15
  from pydantic import model_validator
16
16
 
17
+ from fractal_server import __VERSION__
17
18
  from fractal_server.app.db import AsyncSession
18
19
  from fractal_server.app.db import get_async_db
19
20
  from fractal_server.app.models import UserOAuth
20
21
  from fractal_server.app.models.v2 import TaskGroupActivityV2
21
22
  from fractal_server.app.models.v2 import TaskGroupV2
22
- from fractal_server.app.routes.auth import current_user_act_ver_prof
23
+ from fractal_server.app.routes.auth import get_api_user
23
24
  from fractal_server.app.routes.aux.validate_user_profile import (
24
25
  validate_user_profile,
25
26
  )
@@ -158,7 +159,7 @@ async def collect_tasks_pip(
158
159
  request_data: CollectionRequestData = Depends(parse_request_data),
159
160
  private: bool = False,
160
161
  user_group_id: int | None = None,
161
- user: UserOAuth = Depends(current_user_act_ver_prof),
162
+ user: UserOAuth = Depends(get_api_user),
162
163
  db: AsyncSession = Depends(get_async_db),
163
164
  ) -> TaskGroupActivityRead:
164
165
  """
@@ -332,6 +333,7 @@ async def collect_tasks_pip(
332
333
  action=TaskGroupActivityAction.COLLECT,
333
334
  pkg_name=task_group.pkg_name,
334
335
  version=task_group.version,
336
+ fractal_server_version=__VERSION__,
335
337
  )
336
338
  db.add(task_group_activity)
337
339
  await db.commit()
@@ -12,7 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
12
12
  from fractal_server.app.db import get_async_db
13
13
  from fractal_server.app.models import UserOAuth
14
14
  from fractal_server.app.models.v2 import TaskGroupV2
15
- from fractal_server.app.routes.auth import current_user_act_ver_prof
15
+ from fractal_server.app.routes.auth import get_api_user
16
16
  from fractal_server.app.routes.aux.validate_user_profile import (
17
17
  validate_user_profile,
18
18
  )
@@ -43,7 +43,7 @@ async def collect_task_custom(
43
43
  task_collect: TaskCollectCustom,
44
44
  private: bool = False,
45
45
  user_group_id: int | None = None,
46
- user: UserOAuth = Depends(current_user_act_ver_prof),
46
+ user: UserOAuth = Depends(get_api_user),
47
47
  db: AsyncSession = Depends(get_async_db),
48
48
  ) -> list[TaskRead]:
49
49
  # Get validated resource and profile
@@ -10,6 +10,7 @@ from fastapi import Response
10
10
  from fastapi import UploadFile
11
11
  from fastapi import status
12
12
 
13
+ from fractal_server import __VERSION__
13
14
  from fractal_server.app.db import AsyncSession
14
15
  from fractal_server.app.db import get_async_db
15
16
  from fractal_server.app.models import UserOAuth
@@ -27,7 +28,7 @@ from fractal_server.app.routes.api.v2._aux_functions_tasks import (
27
28
  from fractal_server.app.routes.api.v2._aux_functions_tasks import (
28
29
  _verify_non_duplication_user_constraint,
29
30
  )
30
- from fractal_server.app.routes.auth import current_user_act_ver_prof
31
+ from fractal_server.app.routes.auth import get_api_user
31
32
  from fractal_server.app.routes.aux.validate_user_profile import (
32
33
  validate_user_profile,
33
34
  )
@@ -83,7 +84,7 @@ async def collect_task_pixi(
83
84
  pixi_version: NonEmptyStr | None = Form(None),
84
85
  private: bool = False,
85
86
  user_group_id: int | None = None,
86
- user: UserOAuth = Depends(current_user_act_ver_prof),
87
+ user: UserOAuth = Depends(get_api_user),
87
88
  db: AsyncSession = Depends(get_async_db),
88
89
  ) -> TaskGroupActivityRead:
89
90
  # Get validated resource and profile
@@ -182,6 +183,7 @@ async def collect_task_pixi(
182
183
  action=TaskGroupActivityAction.COLLECT,
183
184
  pkg_name=task_group.pkg_name,
184
185
  version=task_group.version,
186
+ fractal_server_version=__VERSION__,
185
187
  )
186
188
  db.add(task_group_activity)
187
189
  await db.commit()
@@ -4,9 +4,6 @@ from fastapi import APIRouter
4
4
  from fastapi import Depends
5
5
  from fastapi import HTTPException
6
6
  from fastapi import status
7
- from packaging.version import InvalidVersion
8
- from packaging.version import Version
9
- from packaging.version import parse
10
7
  from pydantic.types import AwareDatetime
11
8
  from sqlmodel import or_
12
9
  from sqlmodel import select
@@ -17,13 +14,15 @@ from fractal_server.app.models import LinkUserGroup
17
14
  from fractal_server.app.models import UserOAuth
18
15
  from fractal_server.app.models.v2 import TaskGroupActivityV2
19
16
  from fractal_server.app.models.v2 import TaskGroupV2
20
- from fractal_server.app.routes.auth import current_user_act_ver_prof
17
+ from fractal_server.app.routes.auth import get_api_guest
18
+ from fractal_server.app.routes.auth import get_api_user
21
19
  from fractal_server.app.routes.auth._aux_auth import (
22
20
  _get_default_usergroup_id_or_none,
23
21
  )
24
22
  from fractal_server.app.routes.auth._aux_auth import (
25
23
  _verify_user_belongs_to_group,
26
24
  )
25
+ from fractal_server.app.routes.aux._versions import _version_sort_key
27
26
  from fractal_server.app.schemas.v2 import TaskGroupActivityAction
28
27
  from fractal_server.app.schemas.v2 import TaskGroupActivityRead
29
28
  from fractal_server.app.schemas.v2 import TaskGroupActivityStatus
@@ -42,26 +41,6 @@ router = APIRouter()
42
41
  logger = set_logger(__name__)
43
42
 
44
43
 
45
- def _version_sort_key(
46
- task_group: TaskGroupV2,
47
- ) -> tuple[int, Version | str | None]:
48
- """
49
- Returns a tuple used as (reverse) ordering key for TaskGroups in
50
- `get_task_group_list`.
51
- The TaskGroups with a parsable versions are the first in order,
52
- sorted according to the sorting rules of packaging.version.Version.
53
- Next in order we have the TaskGroups with non-null non-parsable versions,
54
- sorted alphabetically.
55
- Last we have the TaskGroups with null version.
56
- """
57
- if task_group.version is None:
58
- return (0, task_group.version)
59
- try:
60
- return (2, parse(task_group.version))
61
- except InvalidVersion:
62
- return (1, task_group.version)
63
-
64
-
65
44
  @router.get("/activity/", response_model=list[TaskGroupActivityRead])
66
45
  async def get_task_group_activity_list(
67
46
  task_group_activity_id: int | None = None,
@@ -70,7 +49,7 @@ async def get_task_group_activity_list(
70
49
  status: TaskGroupActivityStatus | None = None,
71
50
  action: TaskGroupActivityAction | None = None,
72
51
  timestamp_started_min: AwareDatetime | None = None,
73
- user: UserOAuth = Depends(current_user_act_ver_prof),
52
+ user: UserOAuth = Depends(get_api_guest),
74
53
  db: AsyncSession = Depends(get_async_db),
75
54
  ) -> list[TaskGroupActivityRead]:
76
55
  stm = select(TaskGroupActivityV2).where(
@@ -102,7 +81,7 @@ async def get_task_group_activity_list(
102
81
  )
103
82
  async def get_task_group_activity(
104
83
  task_group_activity_id: int,
105
- user: UserOAuth = Depends(current_user_act_ver_prof),
84
+ user: UserOAuth = Depends(get_api_guest),
106
85
  db: AsyncSession = Depends(get_async_db),
107
86
  ) -> TaskGroupActivityRead:
108
87
  activity = await db.get(TaskGroupActivityV2, task_group_activity_id)
@@ -126,7 +105,7 @@ async def get_task_group_activity(
126
105
 
127
106
  @router.get("/", response_model=list[tuple[str, list[TaskGroupRead]]])
128
107
  async def get_task_group_list(
129
- user: UserOAuth = Depends(current_user_act_ver_prof),
108
+ user: UserOAuth = Depends(get_api_guest),
130
109
  db: AsyncSession = Depends(get_async_db),
131
110
  only_active: bool = False,
132
111
  only_owner: bool = False,
@@ -175,7 +154,7 @@ async def get_task_group_list(
175
154
  await remove_duplicate_task_groups(
176
155
  task_groups=sorted(
177
156
  list(groups),
178
- key=_version_sort_key,
157
+ key=lambda group: _version_sort_key(group.version),
179
158
  reverse=True,
180
159
  ),
181
160
  user_id=user.id,
@@ -194,7 +173,7 @@ async def get_task_group_list(
194
173
  @router.get("/{task_group_id}/", response_model=TaskGroupRead)
195
174
  async def get_task_group(
196
175
  task_group_id: int,
197
- user: UserOAuth = Depends(current_user_act_ver_prof),
176
+ user: UserOAuth = Depends(get_api_guest),
198
177
  db: AsyncSession = Depends(get_async_db),
199
178
  ) -> TaskGroupRead:
200
179
  """
@@ -212,7 +191,7 @@ async def get_task_group(
212
191
  async def patch_task_group(
213
192
  task_group_id: int,
214
193
  task_group_update: TaskGroupUpdate,
215
- user: UserOAuth = Depends(current_user_act_ver_prof),
194
+ user: UserOAuth = Depends(get_api_user),
216
195
  db: AsyncSession = Depends(get_async_db),
217
196
  ) -> TaskGroupRead:
218
197
  """
@@ -5,11 +5,12 @@ from fastapi import HTTPException
5
5
  from fastapi import Response
6
6
  from fastapi import status
7
7
 
8
+ from fractal_server import __VERSION__
8
9
  from fractal_server.app.db import AsyncSession
9
10
  from fractal_server.app.db import get_async_db
10
11
  from fractal_server.app.models import UserOAuth
11
12
  from fractal_server.app.models.v2 import TaskGroupActivityV2
12
- from fractal_server.app.routes.auth import current_user_act_ver_prof
13
+ from fractal_server.app.routes.auth import get_api_user
13
14
  from fractal_server.app.routes.aux.validate_user_profile import (
14
15
  validate_user_profile,
15
16
  )
@@ -51,7 +52,7 @@ async def deactivate_task_group(
51
52
  task_group_id: int,
52
53
  background_tasks: BackgroundTasks,
53
54
  response: Response,
54
- user: UserOAuth = Depends(current_user_act_ver_prof),
55
+ user: UserOAuth = Depends(get_api_user),
55
56
  db: AsyncSession = Depends(get_async_db),
56
57
  ) -> TaskGroupActivityRead:
57
58
  """
@@ -99,6 +100,7 @@ async def deactivate_task_group(
99
100
  ),
100
101
  timestamp_started=get_timestamp(),
101
102
  timestamp_ended=get_timestamp(),
103
+ fractal_server_version=__VERSION__,
102
104
  )
103
105
  db.add(task_group)
104
106
  db.add(task_group_activity)
@@ -114,6 +116,7 @@ async def deactivate_task_group(
114
116
  pkg_name=task_group.pkg_name,
115
117
  version=task_group.version,
116
118
  timestamp_started=get_timestamp(),
119
+ fractal_server_version=__VERSION__,
117
120
  )
118
121
  task_group.active = False
119
122
  db.add(task_group)
@@ -155,7 +158,7 @@ async def reactivate_task_group(
155
158
  task_group_id: int,
156
159
  background_tasks: BackgroundTasks,
157
160
  response: Response,
158
- user: UserOAuth = Depends(current_user_act_ver_prof),
161
+ user: UserOAuth = Depends(get_api_user),
159
162
  db: AsyncSession = Depends(get_async_db),
160
163
  ) -> TaskGroupRead:
161
164
  """
@@ -202,6 +205,7 @@ async def reactivate_task_group(
202
205
  ),
203
206
  timestamp_started=get_timestamp(),
204
207
  timestamp_ended=get_timestamp(),
208
+ fractal_server_version=__VERSION__,
205
209
  )
206
210
  db.add(task_group)
207
211
  db.add(task_group_activity)
@@ -225,6 +229,7 @@ async def reactivate_task_group(
225
229
  pkg_name=task_group.pkg_name,
226
230
  version=task_group.version,
227
231
  timestamp_started=get_timestamp(),
232
+ fractal_server_version=__VERSION__,
228
233
  )
229
234
  db.add(task_group_activity)
230
235
  await db.commit()
@@ -263,7 +268,7 @@ async def delete_task_group(
263
268
  task_group_id: int,
264
269
  background_tasks: BackgroundTasks,
265
270
  response: Response,
266
- user: UserOAuth = Depends(current_user_act_ver_prof),
271
+ user: UserOAuth = Depends(get_api_user),
267
272
  db: AsyncSession = Depends(get_async_db),
268
273
  ) -> TaskGroupActivityRead:
269
274
  """
@@ -288,6 +293,7 @@ async def delete_task_group(
288
293
  pkg_name=task_group.pkg_name,
289
294
  version=(task_group.version or "N/A"),
290
295
  timestamp_started=get_timestamp(),
296
+ fractal_server_version=__VERSION__,
291
297
  )
292
298
  db.add(task_group_activity)
293
299
  await db.commit()
@@ -17,7 +17,8 @@ from fractal_server.app.models import LinkUserGroup
17
17
  from fractal_server.app.models import UserOAuth
18
18
  from fractal_server.app.models.v2 import TaskGroupV2
19
19
  from fractal_server.app.models.v2 import TaskV2
20
- from fractal_server.app.routes.auth import current_user_act_ver_prof
20
+ from fractal_server.app.routes.auth import get_api_guest
21
+ from fractal_server.app.routes.auth import get_api_user
21
22
  from fractal_server.app.schemas.v2 import TaskType
22
23
  from fractal_server.app.schemas.v2 import WorkflowTaskRead
23
24
  from fractal_server.app.schemas.v2 import WorkflowTaskReplace
@@ -77,7 +78,7 @@ class TaskVersionRead(BaseModel):
77
78
  async def get_workflow_version_update_candidates(
78
79
  project_id: int,
79
80
  workflow_id: int,
80
- user: UserOAuth = Depends(current_user_act_ver_prof),
81
+ user: UserOAuth = Depends(get_api_guest),
81
82
  db: AsyncSession = Depends(get_async_db),
82
83
  ) -> list[list[TaskVersionRead]]:
83
84
  workflow = await _get_workflow_check_access(
@@ -180,7 +181,7 @@ async def replace_workflowtask(
180
181
  workflow_task_id: int,
181
182
  task_id: int,
182
183
  replace: WorkflowTaskReplace,
183
- user: UserOAuth = Depends(current_user_act_ver_prof),
184
+ user: UserOAuth = Depends(get_api_user),
184
185
  db: AsyncSession = Depends(get_async_db),
185
186
  ) -> WorkflowTaskRead:
186
187
  # Get objects from database