fractal-server 2.17.0a4__py3-none-any.whl → 2.17.0a6__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/__main__.py +22 -26
- fractal_server/app/models/security.py +19 -21
- fractal_server/app/models/user_settings.py +1 -0
- fractal_server/app/models/v2/task_group.py +1 -0
- fractal_server/app/routes/admin/v2/accounting.py +3 -3
- fractal_server/app/routes/admin/v2/impersonate.py +2 -2
- fractal_server/app/routes/admin/v2/job.py +6 -6
- fractal_server/app/routes/admin/v2/profile.py +18 -4
- fractal_server/app/routes/admin/v2/project.py +2 -2
- fractal_server/app/routes/admin/v2/resource.py +8 -8
- fractal_server/app/routes/admin/v2/task.py +11 -2
- fractal_server/app/routes/admin/v2/task_group.py +16 -12
- fractal_server/app/routes/admin/v2/task_group_lifecycle.py +4 -4
- fractal_server/app/routes/api/__init__.py +14 -5
- fractal_server/app/routes/api/v2/dataset.py +10 -19
- fractal_server/app/routes/api/v2/history.py +8 -8
- fractal_server/app/routes/api/v2/images.py +5 -5
- fractal_server/app/routes/api/v2/job.py +8 -8
- fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
- fractal_server/app/routes/api/v2/project.py +6 -6
- fractal_server/app/routes/api/v2/status_legacy.py +2 -2
- fractal_server/app/routes/api/v2/submit.py +25 -29
- fractal_server/app/routes/api/v2/task.py +6 -7
- fractal_server/app/routes/api/v2/task_collection.py +4 -3
- fractal_server/app/routes/api/v2/task_collection_custom.py +4 -3
- fractal_server/app/routes/api/v2/task_collection_pixi.py +2 -2
- fractal_server/app/routes/api/v2/task_group.py +6 -6
- fractal_server/app/routes/api/v2/task_group_lifecycle.py +4 -4
- fractal_server/app/routes/api/v2/task_version_update.py +3 -3
- fractal_server/app/routes/api/v2/workflow.py +9 -9
- fractal_server/app/routes/api/v2/workflow_import.py +2 -2
- fractal_server/app/routes/api/v2/workflowtask.py +5 -5
- fractal_server/app/routes/auth/__init__.py +34 -5
- fractal_server/app/routes/auth/current_user.py +22 -72
- fractal_server/app/routes/auth/group.py +8 -35
- fractal_server/app/routes/auth/oauth.py +1 -1
- fractal_server/app/routes/auth/register.py +2 -2
- fractal_server/app/routes/auth/users.py +6 -48
- fractal_server/app/schemas/__init__.py +0 -1
- fractal_server/app/schemas/user.py +23 -0
- fractal_server/app/schemas/v2/__init__.py +1 -0
- fractal_server/app/schemas/v2/task_group.py +5 -0
- fractal_server/app/security/__init__.py +134 -46
- fractal_server/app/security/signup_email.py +52 -34
- fractal_server/config/__init__.py +6 -0
- fractal_server/config/_data.py +68 -0
- fractal_server/config/_email.py +10 -47
- fractal_server/config/_main.py +3 -56
- fractal_server/config/_oauth.py +2 -2
- fractal_server/main.py +3 -2
- fractal_server/migrations/versions/f65ee53991e3_user_settings_related.py +67 -0
- fractal_server/runner/executors/slurm_common/base_slurm_runner.py +1 -1
- fractal_server/runner/executors/slurm_common/slurm_config.py +5 -8
- fractal_server/runner/executors/slurm_ssh/runner.py +1 -1
- fractal_server/runner/executors/slurm_sudo/runner.py +1 -1
- fractal_server/runner/v2/_slurm_ssh.py +2 -1
- fractal_server/runner/v2/_slurm_sudo.py +1 -1
- fractal_server/runner/v2/submit_workflow.py +12 -12
- {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/METADATA +4 -6
- {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/RECORD +64 -65
- fractal_server/app/routes/aux/validate_user_settings.py +0 -76
- fractal_server/app/schemas/user_settings.py +0 -63
- fractal_server/app/user_settings.py +0 -32
- {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/WHEEL +0 -0
- {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/entry_points.txt +0 -0
- {fractal_server-2.17.0a4.dist-info → fractal_server-2.17.0a6.dist-info}/licenses/LICENSE +0 -0
|
@@ -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
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
54
|
-
|
|
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
|
)
|
|
@@ -5,7 +5,6 @@ import os
|
|
|
5
5
|
|
|
6
6
|
from fastapi import APIRouter
|
|
7
7
|
from fastapi import Depends
|
|
8
|
-
from fastapi_users import schemas
|
|
9
8
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
10
9
|
from sqlmodel import select
|
|
11
10
|
|
|
@@ -15,23 +14,18 @@ from fractal_server.app.models import Profile
|
|
|
15
14
|
from fractal_server.app.models import Resource
|
|
16
15
|
from fractal_server.app.models import UserGroup
|
|
17
16
|
from fractal_server.app.models import UserOAuth
|
|
18
|
-
from fractal_server.app.
|
|
19
|
-
from fractal_server.app.routes.auth import current_active_user
|
|
17
|
+
from fractal_server.app.routes.auth import current_user_act
|
|
20
18
|
from fractal_server.app.routes.auth._aux_auth import (
|
|
21
19
|
_get_single_user_with_groups,
|
|
22
20
|
)
|
|
23
|
-
from fractal_server.app.routes.aux.validate_user_settings import (
|
|
24
|
-
verify_user_has_settings,
|
|
25
|
-
)
|
|
26
21
|
from fractal_server.app.schemas import UserProfileInfo
|
|
27
|
-
from fractal_server.app.schemas import UserSettingsReadStrict
|
|
28
|
-
from fractal_server.app.schemas import UserSettingsUpdateStrict
|
|
29
22
|
from fractal_server.app.schemas.user import UserRead
|
|
30
23
|
from fractal_server.app.schemas.user import UserUpdate
|
|
31
24
|
from fractal_server.app.schemas.user import UserUpdateStrict
|
|
32
25
|
from fractal_server.app.security import get_user_manager
|
|
33
26
|
from fractal_server.app.security import UserManager
|
|
34
|
-
from fractal_server.config import
|
|
27
|
+
from fractal_server.config import DataAuthScheme
|
|
28
|
+
from fractal_server.config import get_data_settings
|
|
35
29
|
from fractal_server.syringe import Inject
|
|
36
30
|
|
|
37
31
|
router_current_user = APIRouter()
|
|
@@ -40,7 +34,7 @@ router_current_user = APIRouter()
|
|
|
40
34
|
@router_current_user.get("/current-user/", response_model=UserRead)
|
|
41
35
|
async def get_current_user(
|
|
42
36
|
group_ids_names: bool = False,
|
|
43
|
-
user: UserOAuth = Depends(
|
|
37
|
+
user: UserOAuth = Depends(current_user_act),
|
|
44
38
|
db: AsyncSession = Depends(get_async_db),
|
|
45
39
|
):
|
|
46
40
|
"""
|
|
@@ -56,7 +50,7 @@ async def get_current_user(
|
|
|
56
50
|
@router_current_user.patch("/current-user/", response_model=UserRead)
|
|
57
51
|
async def patch_current_user(
|
|
58
52
|
user_update: UserUpdateStrict,
|
|
59
|
-
current_user: UserOAuth = Depends(
|
|
53
|
+
current_user: UserOAuth = Depends(current_user_act),
|
|
60
54
|
user_manager: UserManager = Depends(get_user_manager),
|
|
61
55
|
db: AsyncSession = Depends(get_async_db),
|
|
62
56
|
):
|
|
@@ -71,7 +65,7 @@ async def patch_current_user(
|
|
|
71
65
|
# their own password
|
|
72
66
|
|
|
73
67
|
user = await user_manager.update(update, current_user, safe=True)
|
|
74
|
-
validated_user =
|
|
68
|
+
validated_user = UserOAuth.model_validate(user.model_dump())
|
|
75
69
|
|
|
76
70
|
patched_user = await db.get(
|
|
77
71
|
UserOAuth, validated_user.id, populate_existing=True
|
|
@@ -82,47 +76,12 @@ async def patch_current_user(
|
|
|
82
76
|
return patched_user_with_groups
|
|
83
77
|
|
|
84
78
|
|
|
85
|
-
@router_current_user.get(
|
|
86
|
-
"/current-user/settings/", response_model=UserSettingsReadStrict
|
|
87
|
-
)
|
|
88
|
-
async def get_current_user_settings(
|
|
89
|
-
current_user: UserOAuth = Depends(current_active_user),
|
|
90
|
-
db: AsyncSession = Depends(get_async_db),
|
|
91
|
-
) -> UserSettingsReadStrict:
|
|
92
|
-
verify_user_has_settings(current_user)
|
|
93
|
-
user_settings = await db.get(UserSettings, current_user.user_settings_id)
|
|
94
|
-
return user_settings
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
@router_current_user.patch(
|
|
98
|
-
"/current-user/settings/", response_model=UserSettingsReadStrict
|
|
99
|
-
)
|
|
100
|
-
async def patch_current_user_settings(
|
|
101
|
-
settings_update: UserSettingsUpdateStrict,
|
|
102
|
-
current_user: UserOAuth = Depends(current_active_user),
|
|
103
|
-
db: AsyncSession = Depends(get_async_db),
|
|
104
|
-
) -> UserSettingsReadStrict:
|
|
105
|
-
verify_user_has_settings(current_user)
|
|
106
|
-
current_user_settings = await db.get(
|
|
107
|
-
UserSettings, current_user.user_settings_id
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
for k, v in settings_update.model_dump(exclude_unset=True).items():
|
|
111
|
-
setattr(current_user_settings, k, v)
|
|
112
|
-
|
|
113
|
-
db.add(current_user_settings)
|
|
114
|
-
await db.commit()
|
|
115
|
-
await db.refresh(current_user_settings)
|
|
116
|
-
|
|
117
|
-
return current_user_settings
|
|
118
|
-
|
|
119
|
-
|
|
120
79
|
@router_current_user.get(
|
|
121
80
|
"/current-user/profile-info/",
|
|
122
81
|
response_model=UserProfileInfo,
|
|
123
82
|
)
|
|
124
83
|
async def get_current_user_profile_info(
|
|
125
|
-
current_user: UserOAuth = Depends(
|
|
84
|
+
current_user: UserOAuth = Depends(current_user_act),
|
|
126
85
|
db: AsyncSession = Depends(get_async_db),
|
|
127
86
|
) -> UserProfileInfo:
|
|
128
87
|
stm = (
|
|
@@ -152,45 +111,37 @@ async def get_current_user_profile_info(
|
|
|
152
111
|
"/current-user/allowed-viewer-paths/", response_model=list[str]
|
|
153
112
|
)
|
|
154
113
|
async def get_current_user_allowed_viewer_paths(
|
|
155
|
-
current_user: UserOAuth = Depends(
|
|
114
|
+
current_user: UserOAuth = Depends(current_user_act),
|
|
156
115
|
db: AsyncSession = Depends(get_async_db),
|
|
157
116
|
) -> list[str]:
|
|
158
117
|
"""
|
|
159
118
|
Returns the allowed viewer paths for current user, according to the
|
|
160
|
-
selected
|
|
119
|
+
selected FRACTAL_DATA_AUTH_SCHEME
|
|
161
120
|
"""
|
|
162
121
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if settings.FRACTAL_VIEWER_AUTHORIZATION_SCHEME == "none":
|
|
166
|
-
return []
|
|
122
|
+
data_settings = Inject(get_data_settings)
|
|
167
123
|
|
|
168
124
|
authorized_paths = []
|
|
169
125
|
|
|
170
|
-
|
|
171
|
-
|
|
126
|
+
if data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.NONE:
|
|
127
|
+
return authorized_paths
|
|
172
128
|
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
UserSettings, current_user.user_settings_id
|
|
176
|
-
)
|
|
177
|
-
# If project_dir is set, append it to the list of authorized paths
|
|
178
|
-
if current_user_settings.project_dir is not None:
|
|
179
|
-
authorized_paths.append(current_user_settings.project_dir)
|
|
129
|
+
# Append `project_dir` to the list of authorized paths
|
|
130
|
+
authorized_paths.append(current_user.project_dir)
|
|
180
131
|
|
|
181
132
|
# If auth scheme is "users-folders" and `slurm_user` is set,
|
|
182
133
|
# build and append the user folder
|
|
183
134
|
if (
|
|
184
|
-
|
|
185
|
-
and
|
|
135
|
+
data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.USERS_FOLDERS
|
|
136
|
+
and current_user.profile_id is not None
|
|
186
137
|
):
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
base_folder
|
|
190
|
-
|
|
191
|
-
|
|
138
|
+
profile = await db.get(Profile, current_user.profile_id)
|
|
139
|
+
if profile is not None and profile.username is not None:
|
|
140
|
+
base_folder = data_settings.FRACTAL_DATA_BASE_FOLDER
|
|
141
|
+
user_folder = os.path.join(base_folder, profile.username)
|
|
142
|
+
authorized_paths.append(user_folder)
|
|
192
143
|
|
|
193
|
-
if
|
|
144
|
+
if data_settings.FRACTAL_DATA_AUTH_SCHEME == DataAuthScheme.VIEWER_PATHS:
|
|
194
145
|
# Returns the union of `viewer_paths` for all user's groups
|
|
195
146
|
cmd = (
|
|
196
147
|
select(UserGroup.viewer_paths)
|
|
@@ -207,7 +158,6 @@ async def get_current_user_allowed_viewer_paths(
|
|
|
207
158
|
for _viewer_paths in viewer_paths_nested
|
|
208
159
|
for path in _viewer_paths
|
|
209
160
|
}
|
|
210
|
-
|
|
211
161
|
authorized_paths.extend(all_viewer_paths_set)
|
|
212
162
|
|
|
213
163
|
return authorized_paths
|
|
@@ -9,7 +9,7 @@ from fastapi import status
|
|
|
9
9
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
10
10
|
from sqlmodel import select
|
|
11
11
|
|
|
12
|
-
from . import
|
|
12
|
+
from . import current_superuser_act
|
|
13
13
|
from ._aux_auth import _get_default_usergroup_id
|
|
14
14
|
from ._aux_auth import _get_single_usergroup_with_user_ids
|
|
15
15
|
from ._aux_auth import _user_or_404
|
|
@@ -18,11 +18,9 @@ from fractal_server.app.db import get_async_db
|
|
|
18
18
|
from fractal_server.app.models import LinkUserGroup
|
|
19
19
|
from fractal_server.app.models import UserGroup
|
|
20
20
|
from fractal_server.app.models import UserOAuth
|
|
21
|
-
from fractal_server.app.models import UserSettings
|
|
22
21
|
from fractal_server.app.schemas.user_group import UserGroupCreate
|
|
23
22
|
from fractal_server.app.schemas.user_group import UserGroupRead
|
|
24
23
|
from fractal_server.app.schemas.user_group import UserGroupUpdate
|
|
25
|
-
from fractal_server.app.schemas.user_settings import UserSettingsUpdate
|
|
26
24
|
from fractal_server.app.security import FRACTAL_DEFAULT_GROUP_NAME
|
|
27
25
|
from fractal_server.logger import set_logger
|
|
28
26
|
|
|
@@ -36,7 +34,7 @@ router_group = APIRouter()
|
|
|
36
34
|
)
|
|
37
35
|
async def get_list_user_groups(
|
|
38
36
|
user_ids: bool = False,
|
|
39
|
-
user: UserOAuth = Depends(
|
|
37
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
40
38
|
db: AsyncSession = Depends(get_async_db),
|
|
41
39
|
) -> list[UserGroupRead]:
|
|
42
40
|
# Get all groups
|
|
@@ -70,7 +68,7 @@ async def get_list_user_groups(
|
|
|
70
68
|
)
|
|
71
69
|
async def get_single_user_group(
|
|
72
70
|
group_id: int,
|
|
73
|
-
user: UserOAuth = Depends(
|
|
71
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
74
72
|
db: AsyncSession = Depends(get_async_db),
|
|
75
73
|
) -> UserGroupRead:
|
|
76
74
|
group = await _get_single_usergroup_with_user_ids(group_id=group_id, db=db)
|
|
@@ -84,7 +82,7 @@ async def get_single_user_group(
|
|
|
84
82
|
)
|
|
85
83
|
async def create_single_group(
|
|
86
84
|
group_create: UserGroupCreate,
|
|
87
|
-
user: UserOAuth = Depends(
|
|
85
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
88
86
|
db: AsyncSession = Depends(get_async_db),
|
|
89
87
|
) -> UserGroupRead:
|
|
90
88
|
# Check that name is not already in use
|
|
@@ -116,7 +114,7 @@ async def create_single_group(
|
|
|
116
114
|
async def update_single_group(
|
|
117
115
|
group_id: int,
|
|
118
116
|
group_update: UserGroupUpdate,
|
|
119
|
-
user: UserOAuth = Depends(
|
|
117
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
120
118
|
db: AsyncSession = Depends(get_async_db),
|
|
121
119
|
) -> UserGroupRead:
|
|
122
120
|
group = await _usergroup_or_404(group_id, db)
|
|
@@ -137,7 +135,7 @@ async def update_single_group(
|
|
|
137
135
|
@router_group.delete("/group/{group_id}/", status_code=204)
|
|
138
136
|
async def delete_single_group(
|
|
139
137
|
group_id: int,
|
|
140
|
-
user: UserOAuth = Depends(
|
|
138
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
141
139
|
db: AsyncSession = Depends(get_async_db),
|
|
142
140
|
) -> Response:
|
|
143
141
|
group = await _usergroup_or_404(group_id, db)
|
|
@@ -159,36 +157,11 @@ async def delete_single_group(
|
|
|
159
157
|
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
|
160
158
|
|
|
161
159
|
|
|
162
|
-
@router_group.patch("/group/{group_id}/user-settings/", status_code=200)
|
|
163
|
-
async def patch_user_settings_bulk(
|
|
164
|
-
group_id: int,
|
|
165
|
-
settings_update: UserSettingsUpdate,
|
|
166
|
-
superuser: UserOAuth = Depends(current_active_superuser),
|
|
167
|
-
db: AsyncSession = Depends(get_async_db),
|
|
168
|
-
):
|
|
169
|
-
await _usergroup_or_404(group_id, db)
|
|
170
|
-
res = await db.execute(
|
|
171
|
-
select(UserSettings)
|
|
172
|
-
.join(UserOAuth)
|
|
173
|
-
.where(LinkUserGroup.user_id == UserOAuth.id)
|
|
174
|
-
.where(LinkUserGroup.group_id == group_id)
|
|
175
|
-
)
|
|
176
|
-
settings_list = res.scalars().all()
|
|
177
|
-
update = settings_update.model_dump(exclude_unset=True)
|
|
178
|
-
for settings in settings_list:
|
|
179
|
-
for k, v in update.items():
|
|
180
|
-
setattr(settings, k, v)
|
|
181
|
-
db.add(settings)
|
|
182
|
-
await db.commit()
|
|
183
|
-
|
|
184
|
-
return Response(status_code=status.HTTP_200_OK)
|
|
185
|
-
|
|
186
|
-
|
|
187
160
|
@router_group.post("/group/{group_id}/add-user/{user_id}/", status_code=200)
|
|
188
161
|
async def add_user_to_group(
|
|
189
162
|
group_id: int,
|
|
190
163
|
user_id: int,
|
|
191
|
-
superuser: UserOAuth = Depends(
|
|
164
|
+
superuser: UserOAuth = Depends(current_superuser_act),
|
|
192
165
|
db: AsyncSession = Depends(get_async_db),
|
|
193
166
|
) -> UserGroupRead:
|
|
194
167
|
await _usergroup_or_404(group_id, db)
|
|
@@ -212,7 +185,7 @@ async def add_user_to_group(
|
|
|
212
185
|
async def remove_user_from_group(
|
|
213
186
|
group_id: int,
|
|
214
187
|
user_id: int,
|
|
215
|
-
superuser: UserOAuth = Depends(
|
|
188
|
+
superuser: UserOAuth = Depends(current_superuser_act),
|
|
216
189
|
db: AsyncSession = Depends(get_async_db),
|
|
217
190
|
) -> UserGroupRead:
|
|
218
191
|
# Check that user and group exist
|
|
@@ -29,7 +29,7 @@ def _create_client_oidc(cfg: OAuthSettings) -> OpenID:
|
|
|
29
29
|
return OpenID(
|
|
30
30
|
client_id=cfg.OAUTH_CLIENT_ID.get_secret_value(),
|
|
31
31
|
client_secret=cfg.OAUTH_CLIENT_SECRET.get_secret_value(),
|
|
32
|
-
openid_configuration_endpoint=cfg.OAUTH_OIDC_CONFIG_ENDPOINT,
|
|
32
|
+
openid_configuration_endpoint=cfg.OAUTH_OIDC_CONFIG_ENDPOINT.get_secret_value(), # noqa
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
|
|
@@ -4,7 +4,7 @@ Definition of `/auth/register/` routes.
|
|
|
4
4
|
from fastapi import APIRouter
|
|
5
5
|
from fastapi import Depends
|
|
6
6
|
|
|
7
|
-
from . import
|
|
7
|
+
from . import current_superuser_act
|
|
8
8
|
from . import fastapi_users
|
|
9
9
|
from ...schemas.user import UserCreate
|
|
10
10
|
from ...schemas.user import UserRead
|
|
@@ -13,7 +13,7 @@ router_register = APIRouter()
|
|
|
13
13
|
|
|
14
14
|
router_register.include_router(
|
|
15
15
|
fastapi_users.get_register_router(UserRead, UserCreate),
|
|
16
|
-
dependencies=[Depends(
|
|
16
|
+
dependencies=[Depends(current_superuser_act)],
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
|