fractal-server 2.18.6__py3-none-any.whl → 2.19.0a0__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/models/security.py +16 -0
- fractal_server/app/routes/admin/v2/sharing.py +47 -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/dataset.py +9 -8
- fractal_server/app/routes/api/v2/history.py +8 -8
- fractal_server/app/routes/api/v2/images.py +6 -5
- fractal_server/app/routes/api/v2/job.py +10 -9
- fractal_server/app/routes/api/v2/pre_submission_checks.py +3 -3
- fractal_server/app/routes/api/v2/project.py +7 -6
- fractal_server/app/routes/api/v2/sharing.py +17 -9
- fractal_server/app/routes/api/v2/status_legacy.py +2 -2
- fractal_server/app/routes/api/v2/submit.py +2 -2
- fractal_server/app/routes/api/v2/task.py +7 -6
- fractal_server/app/routes/api/v2/task_collection.py +2 -2
- fractal_server/app/routes/api/v2/task_collection_custom.py +2 -2
- fractal_server/app/routes/api/v2/task_collection_pixi.py +2 -2
- fractal_server/app/routes/api/v2/task_group.py +7 -6
- fractal_server/app/routes/api/v2/task_group_lifecycle.py +4 -4
- fractal_server/app/routes/api/v2/task_version_update.py +4 -3
- fractal_server/app/routes/api/v2/workflow.py +9 -8
- fractal_server/app/routes/api/v2/workflow_import.py +2 -2
- fractal_server/app/routes/api/v2/workflowtask.py +6 -5
- fractal_server/app/routes/auth/__init__.py +18 -1
- fractal_server/app/routes/auth/users.py +11 -0
- fractal_server/app/schemas/user.py +7 -0
- fractal_server/migrations/versions/e53dc51fdf93_add_useroauth_is_guest.py +36 -0
- {fractal_server-2.18.6.dist-info → fractal_server-2.19.0a0.dist-info}/METADATA +1 -1
- {fractal_server-2.18.6.dist-info → fractal_server-2.19.0a0.dist-info}/RECORD +34 -31
- {fractal_server-2.18.6.dist-info → fractal_server-2.19.0a0.dist-info}/WHEEL +0 -0
- {fractal_server-2.18.6.dist-info → fractal_server-2.19.0a0.dist-info}/entry_points.txt +0 -0
- {fractal_server-2.18.6.dist-info → fractal_server-2.19.0a0.dist-info}/licenses/LICENSE +0 -0
fractal_server/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__VERSION__ = "2.
|
|
1
|
+
__VERSION__ = "2.19.0a0"
|
|
@@ -7,6 +7,8 @@ from sqlalchemy import Column
|
|
|
7
7
|
from sqlalchemy import String
|
|
8
8
|
from sqlalchemy.dialects.postgresql import ARRAY
|
|
9
9
|
from sqlalchemy.types import DateTime
|
|
10
|
+
from sqlmodel import BOOLEAN
|
|
11
|
+
from sqlmodel import CheckConstraint
|
|
10
12
|
from sqlmodel import Field
|
|
11
13
|
from sqlmodel import Relationship
|
|
12
14
|
from sqlmodel import SQLModel
|
|
@@ -100,6 +102,13 @@ class UserOAuth(SQLModel, table=True):
|
|
|
100
102
|
is_active: bool = Field(default=True, nullable=False)
|
|
101
103
|
is_superuser: bool = Field(default=False, nullable=False)
|
|
102
104
|
is_verified: bool = Field(default=False, nullable=False)
|
|
105
|
+
is_guest: bool = Field(
|
|
106
|
+
sa_column=Column(
|
|
107
|
+
BOOLEAN,
|
|
108
|
+
server_default="false",
|
|
109
|
+
nullable=False,
|
|
110
|
+
),
|
|
111
|
+
)
|
|
103
112
|
|
|
104
113
|
oauth_accounts: list["OAuthAccount"] = Relationship(
|
|
105
114
|
back_populates="user",
|
|
@@ -120,6 +129,13 @@ class UserOAuth(SQLModel, table=True):
|
|
|
120
129
|
sa_column=Column(ARRAY(String), server_default="{}"),
|
|
121
130
|
)
|
|
122
131
|
|
|
132
|
+
__table_args__ = (
|
|
133
|
+
CheckConstraint(
|
|
134
|
+
"NOT (is_superuser AND is_guest)",
|
|
135
|
+
name="superuser_is_not_guest",
|
|
136
|
+
),
|
|
137
|
+
)
|
|
138
|
+
|
|
123
139
|
|
|
124
140
|
class UserGroup(SQLModel, table=True):
|
|
125
141
|
"""
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
from fastapi import APIRouter
|
|
2
2
|
from fastapi import Depends
|
|
3
|
+
from fastapi import HTTPException
|
|
4
|
+
from fastapi import Response
|
|
5
|
+
from fastapi import status
|
|
3
6
|
from sqlalchemy import func
|
|
4
7
|
from sqlmodel import select
|
|
5
8
|
|
|
@@ -8,11 +11,16 @@ from fractal_server.app.db import get_async_db
|
|
|
8
11
|
from fractal_server.app.models import LinkUserProjectV2
|
|
9
12
|
from fractal_server.app.models import UserOAuth
|
|
10
13
|
from fractal_server.app.models.v2 import ProjectV2
|
|
14
|
+
from fractal_server.app.routes.api.v2._aux_functions_sharing import (
|
|
15
|
+
get_pending_invitation_or_404,
|
|
16
|
+
)
|
|
11
17
|
from fractal_server.app.routes.auth import current_superuser_act
|
|
18
|
+
from fractal_server.app.routes.auth._aux_auth import _user_or_404
|
|
12
19
|
from fractal_server.app.routes.pagination import PaginationRequest
|
|
13
20
|
from fractal_server.app.routes.pagination import PaginationResponse
|
|
14
21
|
from fractal_server.app.routes.pagination import get_pagination_params
|
|
15
22
|
from fractal_server.app.schemas.v2 import LinkUserProjectRead
|
|
23
|
+
from fractal_server.app.schemas.v2.sharing import ProjectPermissions
|
|
16
24
|
|
|
17
25
|
router = APIRouter()
|
|
18
26
|
|
|
@@ -101,3 +109,42 @@ async def view_link_user_project(
|
|
|
101
109
|
for linkuserproject, user_email, project_name in items
|
|
102
110
|
],
|
|
103
111
|
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@router.post("/verify/", status_code=200)
|
|
115
|
+
async def verify_invitation_for_guest(
|
|
116
|
+
guest_user_id: int,
|
|
117
|
+
project_id: int,
|
|
118
|
+
superuser: UserOAuth = Depends(current_superuser_act),
|
|
119
|
+
db: AsyncSession = Depends(get_async_db),
|
|
120
|
+
) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Verify the invitation to join a project for a guest user
|
|
123
|
+
|
|
124
|
+
Note that a guest user would not be allowed to do this themselves.
|
|
125
|
+
"""
|
|
126
|
+
# Get user and verify that they actually are a guest
|
|
127
|
+
guest_user = await _user_or_404(guest_user_id, db)
|
|
128
|
+
if not guest_user.is_guest:
|
|
129
|
+
raise HTTPException(
|
|
130
|
+
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
131
|
+
detail="Cannot accept invitations for non-guest users.",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Find verification and check that permissions are set to R
|
|
135
|
+
link = await get_pending_invitation_or_404(
|
|
136
|
+
user_id=guest_user_id, project_id=project_id, db=db
|
|
137
|
+
)
|
|
138
|
+
if link.permissions != ProjectPermissions.READ:
|
|
139
|
+
raise HTTPException(
|
|
140
|
+
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
141
|
+
detail=(
|
|
142
|
+
"Guest users can only have 'r' permission "
|
|
143
|
+
f"(given: '{link.permissions}')"
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
# Mark the invitation as verified
|
|
147
|
+
link.is_verified = True
|
|
148
|
+
await db.commit()
|
|
149
|
+
|
|
150
|
+
return Response(status_code=status.HTTP_200_OK)
|
|
@@ -1,57 +1,9 @@
|
|
|
1
|
-
"""
|
|
2
|
-
`api` module
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
1
|
from fastapi import APIRouter
|
|
6
|
-
from fastapi import Depends
|
|
7
2
|
|
|
8
|
-
import
|
|
9
|
-
from
|
|
10
|
-
from fractal_server.app.routes.auth import current_superuser_act
|
|
11
|
-
from fractal_server.config import get_db_settings
|
|
12
|
-
from fractal_server.config import get_email_settings
|
|
13
|
-
from fractal_server.config import get_oauth_settings
|
|
14
|
-
from fractal_server.config import get_settings
|
|
15
|
-
from fractal_server.syringe import Inject
|
|
3
|
+
from .alive import router as router_alive
|
|
4
|
+
from .settings import router as router_settings
|
|
16
5
|
|
|
17
6
|
router_api = APIRouter()
|
|
18
7
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
async def alive():
|
|
22
|
-
return dict(
|
|
23
|
-
alive=True,
|
|
24
|
-
version=fractal_server.__VERSION__,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@router_api.get("/settings/app/")
|
|
29
|
-
async def view_settings(
|
|
30
|
-
user: UserOAuth = Depends(current_superuser_act),
|
|
31
|
-
):
|
|
32
|
-
settings = Inject(get_settings)
|
|
33
|
-
return settings.model_dump()
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@router_api.get("/settings/database/")
|
|
37
|
-
async def view_db_settings(
|
|
38
|
-
user: UserOAuth = Depends(current_superuser_act),
|
|
39
|
-
):
|
|
40
|
-
settings = Inject(get_db_settings)
|
|
41
|
-
return settings.model_dump()
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@router_api.get("/settings/email/")
|
|
45
|
-
async def view_email_settings(
|
|
46
|
-
user: UserOAuth = Depends(current_superuser_act),
|
|
47
|
-
):
|
|
48
|
-
settings = Inject(get_email_settings)
|
|
49
|
-
return settings.model_dump()
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@router_api.get("/settings/oauth/")
|
|
53
|
-
async def view_oauth_settings(
|
|
54
|
-
user: UserOAuth = Depends(current_superuser_act),
|
|
55
|
-
):
|
|
56
|
-
settings = Inject(get_oauth_settings)
|
|
57
|
-
return settings.model_dump()
|
|
8
|
+
router_api.include_router(router_alive)
|
|
9
|
+
router_api.include_router(router_settings)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from fastapi import APIRouter
|
|
2
|
+
from fastapi import Depends
|
|
3
|
+
|
|
4
|
+
from fractal_server.app.models import UserOAuth
|
|
5
|
+
from fractal_server.app.routes.auth import current_superuser_act
|
|
6
|
+
from fractal_server.config import get_db_settings
|
|
7
|
+
from fractal_server.config import get_email_settings
|
|
8
|
+
from fractal_server.config import get_oauth_settings
|
|
9
|
+
from fractal_server.config import get_settings
|
|
10
|
+
from fractal_server.syringe import Inject
|
|
11
|
+
|
|
12
|
+
router = APIRouter()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@router.get("/settings/app/")
|
|
16
|
+
async def view_settings(
|
|
17
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
18
|
+
):
|
|
19
|
+
settings = Inject(get_settings)
|
|
20
|
+
return settings.model_dump()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@router.get("/settings/database/")
|
|
24
|
+
async def view_db_settings(
|
|
25
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
26
|
+
):
|
|
27
|
+
settings = Inject(get_db_settings)
|
|
28
|
+
return settings.model_dump()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@router.get("/settings/email/")
|
|
32
|
+
async def view_email_settings(
|
|
33
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
34
|
+
):
|
|
35
|
+
settings = Inject(get_email_settings)
|
|
36
|
+
return settings.model_dump()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@router.get("/settings/oauth/")
|
|
40
|
+
async def view_oauth_settings(
|
|
41
|
+
user: UserOAuth = Depends(current_superuser_act),
|
|
42
|
+
):
|
|
43
|
+
settings = Inject(get_oauth_settings)
|
|
44
|
+
return settings.model_dump()
|
|
@@ -13,7 +13,8 @@ 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 DatasetV2
|
|
15
15
|
from fractal_server.app.models.v2 import JobV2
|
|
16
|
-
from fractal_server.app.routes.auth import
|
|
16
|
+
from fractal_server.app.routes.auth import get_api_guest
|
|
17
|
+
from fractal_server.app.routes.auth import get_api_user
|
|
17
18
|
from fractal_server.app.schemas.v2 import DatasetCreate
|
|
18
19
|
from fractal_server.app.schemas.v2 import DatasetRead
|
|
19
20
|
from fractal_server.app.schemas.v2 import DatasetUpdate
|
|
@@ -38,7 +39,7 @@ router = APIRouter()
|
|
|
38
39
|
async def create_dataset(
|
|
39
40
|
project_id: int,
|
|
40
41
|
dataset: DatasetCreate,
|
|
41
|
-
user: UserOAuth = Depends(
|
|
42
|
+
user: UserOAuth = Depends(get_api_user),
|
|
42
43
|
db: AsyncSession = Depends(get_async_db),
|
|
43
44
|
) -> DatasetRead | None:
|
|
44
45
|
"""
|
|
@@ -96,7 +97,7 @@ async def create_dataset(
|
|
|
96
97
|
)
|
|
97
98
|
async def read_dataset_list(
|
|
98
99
|
project_id: int,
|
|
99
|
-
user: UserOAuth = Depends(
|
|
100
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
100
101
|
db: AsyncSession = Depends(get_async_db),
|
|
101
102
|
) -> list[DatasetRead] | None:
|
|
102
103
|
"""
|
|
@@ -126,7 +127,7 @@ async def read_dataset_list(
|
|
|
126
127
|
async def read_dataset(
|
|
127
128
|
project_id: int,
|
|
128
129
|
dataset_id: int,
|
|
129
|
-
user: UserOAuth = Depends(
|
|
130
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
130
131
|
db: AsyncSession = Depends(get_async_db),
|
|
131
132
|
) -> DatasetRead | None:
|
|
132
133
|
"""
|
|
@@ -151,7 +152,7 @@ async def update_dataset(
|
|
|
151
152
|
project_id: int,
|
|
152
153
|
dataset_id: int,
|
|
153
154
|
dataset_update: DatasetUpdate,
|
|
154
|
-
user: UserOAuth = Depends(
|
|
155
|
+
user: UserOAuth = Depends(get_api_user),
|
|
155
156
|
db: AsyncSession = Depends(get_async_db),
|
|
156
157
|
) -> DatasetRead | None:
|
|
157
158
|
"""
|
|
@@ -182,7 +183,7 @@ async def update_dataset(
|
|
|
182
183
|
async def delete_dataset(
|
|
183
184
|
project_id: int,
|
|
184
185
|
dataset_id: int,
|
|
185
|
-
user: UserOAuth = Depends(
|
|
186
|
+
user: UserOAuth = Depends(get_api_user),
|
|
186
187
|
db: AsyncSession = Depends(get_async_db),
|
|
187
188
|
) -> Response:
|
|
188
189
|
"""
|
|
@@ -226,7 +227,7 @@ async def delete_dataset(
|
|
|
226
227
|
async def export_dataset(
|
|
227
228
|
project_id: int,
|
|
228
229
|
dataset_id: int,
|
|
229
|
-
user: UserOAuth = Depends(
|
|
230
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
230
231
|
db: AsyncSession = Depends(get_async_db),
|
|
231
232
|
) -> DatasetExport | None:
|
|
232
233
|
"""
|
|
@@ -252,7 +253,7 @@ async def export_dataset(
|
|
|
252
253
|
async def import_dataset(
|
|
253
254
|
project_id: int,
|
|
254
255
|
dataset: DatasetImport,
|
|
255
|
-
user: UserOAuth = Depends(
|
|
256
|
+
user: UserOAuth = Depends(get_api_user),
|
|
256
257
|
db: AsyncSession = Depends(get_async_db),
|
|
257
258
|
) -> DatasetRead | None:
|
|
258
259
|
"""
|
|
@@ -14,7 +14,7 @@ from fractal_server.app.models.v2 import HistoryRun
|
|
|
14
14
|
from fractal_server.app.models.v2 import HistoryUnit
|
|
15
15
|
from fractal_server.app.models.v2 import JobV2
|
|
16
16
|
from fractal_server.app.models.v2 import TaskV2
|
|
17
|
-
from fractal_server.app.routes.auth import
|
|
17
|
+
from fractal_server.app.routes.auth import get_api_guest
|
|
18
18
|
from fractal_server.app.routes.pagination import PaginationRequest
|
|
19
19
|
from fractal_server.app.routes.pagination import PaginationResponse
|
|
20
20
|
from fractal_server.app.routes.pagination import get_pagination_params
|
|
@@ -71,7 +71,7 @@ async def get_workflow_tasks_statuses(
|
|
|
71
71
|
project_id: int,
|
|
72
72
|
dataset_id: int,
|
|
73
73
|
workflow_id: int,
|
|
74
|
-
user: UserOAuth = Depends(
|
|
74
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
75
75
|
db: AsyncSession = Depends(get_async_db),
|
|
76
76
|
) -> JSONResponse:
|
|
77
77
|
# Access control
|
|
@@ -186,7 +186,7 @@ async def get_history_run_list(
|
|
|
186
186
|
project_id: int,
|
|
187
187
|
dataset_id: int,
|
|
188
188
|
workflowtask_id: int,
|
|
189
|
-
user: UserOAuth = Depends(
|
|
189
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
190
190
|
db: AsyncSession = Depends(get_async_db),
|
|
191
191
|
) -> list[HistoryRunReadAggregated]:
|
|
192
192
|
# Access control
|
|
@@ -279,7 +279,7 @@ async def get_history_run_units(
|
|
|
279
279
|
workflowtask_id: int,
|
|
280
280
|
history_run_id: int,
|
|
281
281
|
unit_status: HistoryUnitStatus | None = None,
|
|
282
|
-
user: UserOAuth = Depends(
|
|
282
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
283
283
|
db: AsyncSession = Depends(get_async_db),
|
|
284
284
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
|
285
285
|
) -> PaginationResponse[HistoryUnitRead]:
|
|
@@ -339,7 +339,7 @@ async def get_history_images(
|
|
|
339
339
|
dataset_id: int,
|
|
340
340
|
workflowtask_id: int,
|
|
341
341
|
request_body: ImageQuery,
|
|
342
|
-
user: UserOAuth = Depends(
|
|
342
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
343
343
|
db: AsyncSession = Depends(get_async_db),
|
|
344
344
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
|
345
345
|
) -> ImagePage:
|
|
@@ -423,7 +423,7 @@ async def get_history_images(
|
|
|
423
423
|
async def get_image_log(
|
|
424
424
|
project_id: int,
|
|
425
425
|
request_data: ImageLogsRequest,
|
|
426
|
-
user: UserOAuth = Depends(
|
|
426
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
427
427
|
db: AsyncSession = Depends(get_async_db),
|
|
428
428
|
) -> JSONResponse:
|
|
429
429
|
# Access control
|
|
@@ -482,7 +482,7 @@ async def get_history_unit_log(
|
|
|
482
482
|
history_unit_id: int,
|
|
483
483
|
workflowtask_id: int,
|
|
484
484
|
dataset_id: int,
|
|
485
|
-
user: UserOAuth = Depends(
|
|
485
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
486
486
|
db: AsyncSession = Depends(get_async_db),
|
|
487
487
|
) -> JSONResponse:
|
|
488
488
|
# Access control
|
|
@@ -535,7 +535,7 @@ async def get_history_unit_log(
|
|
|
535
535
|
async def get_dataset_history(
|
|
536
536
|
project_id: int,
|
|
537
537
|
dataset_id: int,
|
|
538
|
-
user: UserOAuth = Depends(
|
|
538
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
539
539
|
db: AsyncSession = Depends(get_async_db),
|
|
540
540
|
) -> list[HistoryRunRead]:
|
|
541
541
|
"""
|
|
@@ -12,7 +12,8 @@ from fractal_server.app.db import AsyncSession
|
|
|
12
12
|
from fractal_server.app.db import get_async_db
|
|
13
13
|
from fractal_server.app.models import HistoryImageCache
|
|
14
14
|
from fractal_server.app.models import UserOAuth
|
|
15
|
-
from fractal_server.app.routes.auth import
|
|
15
|
+
from fractal_server.app.routes.auth import get_api_guest
|
|
16
|
+
from fractal_server.app.routes.auth import get_api_user
|
|
16
17
|
from fractal_server.app.routes.pagination import PaginationRequest
|
|
17
18
|
from fractal_server.app.routes.pagination import PaginationResponse
|
|
18
19
|
from fractal_server.app.routes.pagination import get_pagination_params
|
|
@@ -62,7 +63,7 @@ async def post_new_image(
|
|
|
62
63
|
project_id: int,
|
|
63
64
|
dataset_id: int,
|
|
64
65
|
new_image: SingleImage,
|
|
65
|
-
user: UserOAuth = Depends(
|
|
66
|
+
user: UserOAuth = Depends(get_api_user),
|
|
66
67
|
db: AsyncSession = Depends(get_async_db),
|
|
67
68
|
) -> Response:
|
|
68
69
|
output = await _get_dataset_check_access(
|
|
@@ -118,7 +119,7 @@ async def query_dataset_images(
|
|
|
118
119
|
dataset_id: int,
|
|
119
120
|
query: ImageQueryWithZarrUrl | None = None,
|
|
120
121
|
pagination: PaginationRequest = Depends(get_pagination_params),
|
|
121
|
-
user: UserOAuth = Depends(
|
|
122
|
+
user: UserOAuth = Depends(get_api_guest),
|
|
122
123
|
db: AsyncSession = Depends(get_async_db),
|
|
123
124
|
) -> ImagePage:
|
|
124
125
|
page = pagination.page
|
|
@@ -193,7 +194,7 @@ async def delete_dataset_images(
|
|
|
193
194
|
project_id: int,
|
|
194
195
|
dataset_id: int,
|
|
195
196
|
zarr_url: str,
|
|
196
|
-
user: UserOAuth = Depends(
|
|
197
|
+
user: UserOAuth = Depends(get_api_user),
|
|
197
198
|
db: AsyncSession = Depends(get_async_db),
|
|
198
199
|
) -> Response:
|
|
199
200
|
output = await _get_dataset_check_access(
|
|
@@ -241,7 +242,7 @@ async def patch_dataset_image(
|
|
|
241
242
|
project_id: int,
|
|
242
243
|
dataset_id: int,
|
|
243
244
|
image_update: SingleImageUpdate,
|
|
244
|
-
user: UserOAuth = Depends(
|
|
245
|
+
user: UserOAuth = Depends(get_api_user),
|
|
245
246
|
db: AsyncSession = Depends(get_async_db),
|
|
246
247
|
):
|
|
247
248
|
output = await _get_dataset_check_access(
|
|
@@ -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)
|
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
"""
|
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
"""
|