fractal-server 2.18.5__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.
- fractal_server/__init__.py +1 -1
- fractal_server/app/db/__init__.py +1 -7
- fractal_server/app/models/security.py +16 -0
- fractal_server/app/models/v2/dataset.py +0 -4
- fractal_server/app/models/v2/job.py +4 -0
- fractal_server/app/models/v2/task.py +0 -1
- fractal_server/app/models/v2/task_group.py +4 -0
- fractal_server/app/models/v2/workflow.py +2 -0
- fractal_server/app/models/v2/workflowtask.py +3 -0
- fractal_server/app/routes/admin/v2/job.py +0 -2
- fractal_server/app/routes/admin/v2/sharing.py +47 -0
- fractal_server/app/routes/admin/v2/task.py +0 -5
- fractal_server/app/routes/admin/v2/task_group_lifecycle.py +6 -0
- fractal_server/app/routes/api/__init__.py +4 -52
- fractal_server/app/routes/api/alive.py +13 -0
- fractal_server/app/routes/api/settings.py +44 -0
- fractal_server/app/routes/api/v2/__init__.py +0 -2
- fractal_server/app/routes/api/v2/_aux_functions_task_lifecycle.py +1 -20
- fractal_server/app/routes/api/v2/dataset.py +9 -8
- fractal_server/app/routes/api/v2/history.py +8 -8
- fractal_server/app/routes/api/v2/images.py +6 -6
- fractal_server/app/routes/api/v2/job.py +10 -12
- fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
- fractal_server/app/routes/api/v2/project.py +7 -9
- fractal_server/app/routes/api/v2/sharing.py +17 -9
- fractal_server/app/routes/api/v2/submit.py +5 -3
- fractal_server/app/routes/api/v2/task.py +7 -9
- fractal_server/app/routes/api/v2/task_collection.py +4 -2
- fractal_server/app/routes/api/v2/task_collection_custom.py +2 -2
- fractal_server/app/routes/api/v2/task_collection_pixi.py +4 -2
- fractal_server/app/routes/api/v2/task_group.py +10 -30
- fractal_server/app/routes/api/v2/task_group_lifecycle.py +10 -4
- fractal_server/app/routes/api/v2/task_version_update.py +4 -3
- fractal_server/app/routes/api/v2/workflow.py +10 -11
- fractal_server/app/routes/api/v2/workflow_import.py +14 -45
- fractal_server/app/routes/api/v2/workflowtask.py +7 -12
- fractal_server/app/routes/auth/__init__.py +18 -1
- fractal_server/app/routes/auth/current_user.py +8 -0
- fractal_server/app/routes/auth/oauth.py +3 -1
- fractal_server/app/routes/auth/users.py +11 -0
- fractal_server/app/routes/aux/_versions.py +42 -0
- fractal_server/app/schemas/user.py +7 -0
- fractal_server/app/schemas/v2/__init__.py +0 -1
- fractal_server/app/schemas/v2/dumps.py +0 -1
- fractal_server/app/schemas/v2/task.py +0 -5
- fractal_server/app/schemas/v2/workflow.py +2 -0
- fractal_server/app/schemas/v2/workflowtask.py +6 -2
- fractal_server/app/security/__init__.py +8 -3
- fractal_server/migrations/versions/18a26fcdea5d_drop_dataset_history.py +41 -0
- fractal_server/migrations/versions/1bf8785755f9_add_description_to_workflow_and_.py +53 -0
- fractal_server/migrations/versions/5fb08bf05b14_drop_taskv2_source.py +36 -0
- fractal_server/migrations/versions/cfd13f7954e7_add_fractal_server_version_to_jobv2_and_.py +52 -0
- fractal_server/migrations/versions/e53dc51fdf93_add_useroauth_is_guest.py +36 -0
- fractal_server/runner/executors/local/runner.py +2 -0
- fractal_server/runner/executors/slurm_ssh/runner.py +5 -0
- fractal_server/runner/executors/slurm_sudo/runner.py +5 -0
- fractal_server/runner/v2/runner.py +0 -1
- fractal_server/runner/v2/submit_workflow.py +0 -3
- {fractal_server-2.18.5.dist-info → fractal_server-2.19.0.dist-info}/METADATA +3 -3
- {fractal_server-2.18.5.dist-info → fractal_server-2.19.0.dist-info}/RECORD +63 -56
- {fractal_server-2.18.5.dist-info → fractal_server-2.19.0.dist-info}/WHEEL +1 -1
- fractal_server/app/routes/api/v2/status_legacy.py +0 -156
- {fractal_server-2.18.5.dist-info → fractal_server-2.19.0.dist-info}/entry_points.txt +0 -0
- {fractal_server-2.18.5.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
|
|
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(
|
|
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
|
|
50
|
+
Returns all the jobs from projects linked to the current user
|
|
50
51
|
"""
|
|
51
52
|
stm = (
|
|
52
53
|
select(JobV2)
|
|
@@ -59,7 +60,6 @@ async def get_user_jobs(
|
|
|
59
60
|
)
|
|
60
61
|
res = await db.execute(stm)
|
|
61
62
|
job_list = res.scalars().all()
|
|
62
|
-
await db.close()
|
|
63
63
|
if not log:
|
|
64
64
|
for job in job_list:
|
|
65
65
|
setattr(job, "log", None)
|
|
@@ -74,7 +74,7 @@ async def get_user_jobs(
|
|
|
74
74
|
async def get_workflow_jobs(
|
|
75
75
|
project_id: int,
|
|
76
76
|
workflow_id: int,
|
|
77
|
-
user: UserOAuth = Depends(
|
|
77
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
78
78
|
db: AsyncSession = Depends(get_async_db),
|
|
79
79
|
) -> list[JobRead] | None:
|
|
80
80
|
"""
|
|
@@ -101,7 +101,7 @@ async def get_latest_job(
|
|
|
101
101
|
project_id: int,
|
|
102
102
|
workflow_id: int,
|
|
103
103
|
dataset_id: int,
|
|
104
|
-
user: UserOAuth = Depends(
|
|
104
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
105
105
|
db: AsyncSession = Depends(get_async_db),
|
|
106
106
|
) -> JobRead:
|
|
107
107
|
await _get_workflow_check_access(
|
|
@@ -137,7 +137,7 @@ async def read_job(
|
|
|
137
137
|
project_id: int,
|
|
138
138
|
job_id: int,
|
|
139
139
|
show_tmp_logs: bool = False,
|
|
140
|
-
user: UserOAuth = Depends(
|
|
140
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
141
141
|
db: AsyncSession = Depends(get_async_db),
|
|
142
142
|
) -> JobRead | None:
|
|
143
143
|
"""
|
|
@@ -152,7 +152,6 @@ async def read_job(
|
|
|
152
152
|
db=db,
|
|
153
153
|
)
|
|
154
154
|
job = output["job"]
|
|
155
|
-
await db.close()
|
|
156
155
|
|
|
157
156
|
if show_tmp_logs and (job.status == JobStatusType.SUBMITTED):
|
|
158
157
|
try:
|
|
@@ -171,7 +170,7 @@ async def read_job(
|
|
|
171
170
|
async def download_job_logs(
|
|
172
171
|
project_id: int,
|
|
173
172
|
job_id: int,
|
|
174
|
-
user: UserOAuth = Depends(
|
|
173
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
175
174
|
db: AsyncSession = Depends(get_async_db),
|
|
176
175
|
) -> StreamingResponse:
|
|
177
176
|
"""
|
|
@@ -202,7 +201,7 @@ async def download_job_logs(
|
|
|
202
201
|
)
|
|
203
202
|
async def get_job_list(
|
|
204
203
|
project_id: int,
|
|
205
|
-
user: UserOAuth = Depends(
|
|
204
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
206
205
|
log: bool = True,
|
|
207
206
|
db: AsyncSession = Depends(get_async_db),
|
|
208
207
|
) -> list[JobRead] | None:
|
|
@@ -222,7 +221,6 @@ async def get_job_list(
|
|
|
222
221
|
.order_by(JobV2.start_timestamp.desc())
|
|
223
222
|
)
|
|
224
223
|
job_list = res.scalars().all()
|
|
225
|
-
await db.close()
|
|
226
224
|
if not log:
|
|
227
225
|
for job in job_list:
|
|
228
226
|
setattr(job, "log", None)
|
|
@@ -237,7 +235,7 @@ async def get_job_list(
|
|
|
237
235
|
async def stop_job(
|
|
238
236
|
project_id: int,
|
|
239
237
|
job_id: int,
|
|
240
|
-
user: UserOAuth = Depends(
|
|
238
|
+
user: UserOAuth = Depends(get_api_user),
|
|
241
239
|
db: AsyncSession = Depends(get_async_db),
|
|
242
240
|
) -> Response:
|
|
243
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
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
36
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
36
37
|
db: AsyncSession = Depends(get_async_db),
|
|
37
38
|
) -> list[ProjectV2]:
|
|
38
39
|
"""
|
|
@@ -47,14 +48,13 @@ async def get_list_project(
|
|
|
47
48
|
)
|
|
48
49
|
res = await db.execute(stm)
|
|
49
50
|
project_list = res.scalars().all()
|
|
50
|
-
await db.close()
|
|
51
51
|
return project_list
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
@router.post("/project/", response_model=ProjectRead, status_code=201)
|
|
55
55
|
async def create_project(
|
|
56
56
|
project: ProjectCreate,
|
|
57
|
-
user: UserOAuth = Depends(
|
|
57
|
+
user: UserOAuth = Depends(get_api_user),
|
|
58
58
|
db: AsyncSession = Depends(get_async_db),
|
|
59
59
|
) -> ProjectRead | None:
|
|
60
60
|
"""
|
|
@@ -95,7 +95,7 @@ async def create_project(
|
|
|
95
95
|
@router.get("/project/{project_id}/", response_model=ProjectRead)
|
|
96
96
|
async def read_project(
|
|
97
97
|
project_id: int,
|
|
98
|
-
user: UserOAuth = Depends(
|
|
98
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
99
99
|
db: AsyncSession = Depends(get_async_db),
|
|
100
100
|
) -> ProjectRead | None:
|
|
101
101
|
"""
|
|
@@ -107,7 +107,6 @@ async def read_project(
|
|
|
107
107
|
required_permissions=ProjectPermissions.READ,
|
|
108
108
|
db=db,
|
|
109
109
|
)
|
|
110
|
-
await db.close()
|
|
111
110
|
return project
|
|
112
111
|
|
|
113
112
|
|
|
@@ -115,7 +114,7 @@ async def read_project(
|
|
|
115
114
|
async def update_project(
|
|
116
115
|
project_id: int,
|
|
117
116
|
project_update: ProjectUpdate,
|
|
118
|
-
user: UserOAuth = Depends(
|
|
117
|
+
user: UserOAuth = Depends(get_api_user),
|
|
119
118
|
db: AsyncSession = Depends(get_async_db),
|
|
120
119
|
):
|
|
121
120
|
project = await _get_project_check_access(
|
|
@@ -136,14 +135,13 @@ async def update_project(
|
|
|
136
135
|
|
|
137
136
|
await db.commit()
|
|
138
137
|
await db.refresh(project)
|
|
139
|
-
await db.close()
|
|
140
138
|
return project
|
|
141
139
|
|
|
142
140
|
|
|
143
141
|
@router.delete("/project/{project_id}/", status_code=204)
|
|
144
142
|
async def delete_project(
|
|
145
143
|
project_id: int,
|
|
146
|
-
user: UserOAuth = Depends(
|
|
144
|
+
user: UserOAuth = Depends(get_api_user),
|
|
147
145
|
db: AsyncSession = Depends(get_async_db),
|
|
148
146
|
) -> Response:
|
|
149
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
47
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
47
48
|
db: AsyncSession = Depends(get_async_db),
|
|
48
49
|
) -> list[TaskRead]:
|
|
49
50
|
"""
|
|
@@ -77,7 +78,6 @@ async def get_list_task(
|
|
|
77
78
|
stm = stm.order_by(TaskV2.id)
|
|
78
79
|
res = await db.execute(stm)
|
|
79
80
|
task_list = list(res.scalars().all())
|
|
80
|
-
await db.close()
|
|
81
81
|
if args_schema is False:
|
|
82
82
|
for task in task_list:
|
|
83
83
|
setattr(task, "args_schema_parallel", None)
|
|
@@ -89,7 +89,7 @@ async def get_list_task(
|
|
|
89
89
|
@router.get("/{task_id}/", response_model=TaskRead)
|
|
90
90
|
async def get_task(
|
|
91
91
|
task_id: int,
|
|
92
|
-
user: UserOAuth = Depends(
|
|
92
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
93
93
|
db: AsyncSession = Depends(get_async_db),
|
|
94
94
|
) -> TaskRead:
|
|
95
95
|
"""
|
|
@@ -103,7 +103,7 @@ async def get_task(
|
|
|
103
103
|
async def patch_task(
|
|
104
104
|
task_id: int,
|
|
105
105
|
task_update: TaskUpdate,
|
|
106
|
-
user: UserOAuth = Depends(
|
|
106
|
+
user: UserOAuth = Depends(get_api_user),
|
|
107
107
|
db: AsyncSession = Depends(get_async_db),
|
|
108
108
|
) -> TaskRead | None:
|
|
109
109
|
"""
|
|
@@ -133,7 +133,6 @@ async def patch_task(
|
|
|
133
133
|
|
|
134
134
|
await db.commit()
|
|
135
135
|
await db.refresh(db_task)
|
|
136
|
-
await db.close()
|
|
137
136
|
return db_task
|
|
138
137
|
|
|
139
138
|
|
|
@@ -142,7 +141,7 @@ async def create_task(
|
|
|
142
141
|
task: TaskCreate,
|
|
143
142
|
user_group_id: int | None = None,
|
|
144
143
|
private: bool = False,
|
|
145
|
-
user: UserOAuth = Depends(
|
|
144
|
+
user: UserOAuth = Depends(get_api_user),
|
|
146
145
|
db: AsyncSession = Depends(get_async_db),
|
|
147
146
|
) -> TaskRead | None:
|
|
148
147
|
"""
|
|
@@ -216,7 +215,6 @@ async def create_task(
|
|
|
216
215
|
db.add(db_task_group)
|
|
217
216
|
await db.commit()
|
|
218
217
|
await db.refresh(db_task)
|
|
219
|
-
await db.close()
|
|
220
218
|
|
|
221
219
|
return db_task
|
|
222
220
|
|
|
@@ -224,7 +222,7 @@ async def create_task(
|
|
|
224
222
|
@router.delete("/{task_id}/", status_code=204)
|
|
225
223
|
async def delete_task(
|
|
226
224
|
task_id: int,
|
|
227
|
-
user: UserOAuth = Depends(
|
|
225
|
+
user: UserOAuth = Depends(get_api_user),
|
|
228
226
|
db: AsyncSession = Depends(get_async_db),
|
|
229
227
|
) -> Response:
|
|
230
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
@@ -163,6 +142,7 @@ async def get_task_group_list(
|
|
|
163
142
|
if args_schema is False:
|
|
164
143
|
for taskgroup in task_groups:
|
|
165
144
|
for task in taskgroup.task_list:
|
|
145
|
+
db.expunge(task) # See issue 3101
|
|
166
146
|
setattr(task, "args_schema_non_parallel", None)
|
|
167
147
|
setattr(task, "args_schema_parallel", None)
|
|
168
148
|
|
|
@@ -174,7 +154,7 @@ async def get_task_group_list(
|
|
|
174
154
|
await remove_duplicate_task_groups(
|
|
175
155
|
task_groups=sorted(
|
|
176
156
|
list(groups),
|
|
177
|
-
key=_version_sort_key,
|
|
157
|
+
key=lambda group: _version_sort_key(group.version),
|
|
178
158
|
reverse=True,
|
|
179
159
|
),
|
|
180
160
|
user_id=user.id,
|
|
@@ -193,7 +173,7 @@ async def get_task_group_list(
|
|
|
193
173
|
@router.get("/{task_group_id}/", response_model=TaskGroupRead)
|
|
194
174
|
async def get_task_group(
|
|
195
175
|
task_group_id: int,
|
|
196
|
-
user: UserOAuth = Depends(
|
|
176
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
197
177
|
db: AsyncSession = Depends(get_async_db),
|
|
198
178
|
) -> TaskGroupRead:
|
|
199
179
|
"""
|
|
@@ -211,7 +191,7 @@ async def get_task_group(
|
|
|
211
191
|
async def patch_task_group(
|
|
212
192
|
task_group_id: int,
|
|
213
193
|
task_group_update: TaskGroupUpdate,
|
|
214
|
-
user: UserOAuth = Depends(
|
|
194
|
+
user: UserOAuth = Depends(get_api_user),
|
|
215
195
|
db: AsyncSession = Depends(get_async_db),
|
|
216
196
|
) -> TaskGroupRead:
|
|
217
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
|
|
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(
|
|
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(
|
|
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(
|
|
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()
|