fractal-server 2.3.10__py3-none-any.whl → 2.4.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/__main__.py +25 -2
- fractal_server/app/models/__init__.py +11 -5
- fractal_server/app/models/linkusergroup.py +11 -0
- fractal_server/app/models/security.py +24 -3
- fractal_server/app/models/v1/project.py +1 -1
- fractal_server/app/models/v2/project.py +3 -3
- fractal_server/app/routes/admin/v1.py +14 -14
- fractal_server/app/routes/admin/v2.py +12 -12
- fractal_server/app/routes/api/__init__.py +2 -2
- fractal_server/app/routes/api/v1/_aux_functions.py +2 -2
- fractal_server/app/routes/api/v1/dataset.py +17 -15
- fractal_server/app/routes/api/v1/job.py +11 -9
- fractal_server/app/routes/api/v1/project.py +9 -9
- fractal_server/app/routes/api/v1/task.py +8 -8
- fractal_server/app/routes/api/v1/task_collection.py +5 -5
- fractal_server/app/routes/api/v1/workflow.py +13 -11
- fractal_server/app/routes/api/v1/workflowtask.py +6 -6
- fractal_server/app/routes/api/v2/_aux_functions.py +2 -2
- fractal_server/app/routes/api/v2/dataset.py +11 -11
- fractal_server/app/routes/api/v2/images.py +6 -6
- fractal_server/app/routes/api/v2/job.py +9 -9
- fractal_server/app/routes/api/v2/project.py +7 -7
- fractal_server/app/routes/api/v2/status.py +3 -3
- fractal_server/app/routes/api/v2/submit.py +3 -3
- fractal_server/app/routes/api/v2/task.py +8 -8
- fractal_server/app/routes/api/v2/task_collection.py +5 -5
- fractal_server/app/routes/api/v2/task_collection_custom.py +3 -3
- fractal_server/app/routes/api/v2/task_legacy.py +9 -9
- fractal_server/app/routes/api/v2/workflow.py +11 -11
- fractal_server/app/routes/api/v2/workflowtask.py +6 -6
- fractal_server/app/routes/auth/__init__.py +55 -0
- fractal_server/app/routes/auth/_aux_auth.py +107 -0
- fractal_server/app/routes/auth/current_user.py +60 -0
- fractal_server/app/routes/auth/group.py +176 -0
- fractal_server/app/routes/auth/group_names.py +34 -0
- fractal_server/app/routes/auth/login.py +25 -0
- fractal_server/app/routes/auth/oauth.py +63 -0
- fractal_server/app/routes/auth/register.py +23 -0
- fractal_server/app/routes/auth/router.py +19 -0
- fractal_server/app/routes/auth/users.py +192 -0
- fractal_server/app/runner/v2/__init__.py +1 -5
- fractal_server/app/runner/v2/_slurm_ssh/__init__.py +17 -0
- fractal_server/app/schemas/user.py +11 -0
- fractal_server/app/schemas/user_group.py +65 -0
- fractal_server/app/security/__init__.py +72 -75
- fractal_server/data_migrations/2_4_0.py +61 -0
- fractal_server/main.py +1 -9
- fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py +53 -0
- {fractal_server-2.3.10.dist-info → fractal_server-2.4.0.dist-info}/METADATA +1 -1
- {fractal_server-2.3.10.dist-info → fractal_server-2.4.0.dist-info}/RECORD +54 -41
- fractal_server/app/routes/auth.py +0 -165
- {fractal_server-2.3.10.dist-info → fractal_server-2.4.0.dist-info}/LICENSE +0 -0
- {fractal_server-2.3.10.dist-info → fractal_server-2.4.0.dist-info}/WHEEL +0 -0
- {fractal_server-2.3.10.dist-info → fractal_server-2.4.0.dist-info}/entry_points.txt +0 -0
@@ -29,41 +29,38 @@ All routes are registerd under the `auth/` prefix.
|
|
29
29
|
import contextlib
|
30
30
|
from typing import Any
|
31
31
|
from typing import AsyncGenerator
|
32
|
-
from typing import Dict
|
33
32
|
from typing import Generic
|
34
33
|
from typing import Optional
|
35
34
|
from typing import Type
|
36
35
|
|
37
36
|
from fastapi import Depends
|
37
|
+
from fastapi import Request
|
38
38
|
from fastapi_users import BaseUserManager
|
39
|
-
from fastapi_users import FastAPIUsers
|
40
39
|
from fastapi_users import IntegerIDMixin
|
41
|
-
from fastapi_users.authentication import AuthenticationBackend
|
42
|
-
from fastapi_users.authentication import BearerTransport
|
43
|
-
from fastapi_users.authentication import CookieTransport
|
44
|
-
from fastapi_users.authentication import JWTStrategy
|
45
40
|
from fastapi_users.db.base import BaseUserDatabase
|
46
41
|
from fastapi_users.exceptions import InvalidPasswordException
|
47
42
|
from fastapi_users.exceptions import UserAlreadyExists
|
48
43
|
from fastapi_users.models import ID
|
49
44
|
from fastapi_users.models import OAP
|
50
45
|
from fastapi_users.models import UP
|
51
|
-
from sqlalchemy.exc import IntegrityError
|
52
46
|
from sqlalchemy.ext.asyncio import AsyncSession
|
53
47
|
from sqlalchemy.orm import selectinload
|
54
48
|
from sqlmodel import func
|
55
49
|
from sqlmodel import select
|
56
50
|
|
57
|
-
from ...config import get_settings
|
58
|
-
from ...syringe import Inject
|
59
51
|
from ..db import get_async_db
|
60
|
-
from fractal_server.app.
|
61
|
-
from fractal_server.app.models
|
52
|
+
from fractal_server.app.db import get_sync_db
|
53
|
+
from fractal_server.app.models import LinkUserGroup
|
54
|
+
from fractal_server.app.models import OAuthAccount
|
55
|
+
from fractal_server.app.models import UserGroup
|
56
|
+
from fractal_server.app.models import UserOAuth
|
62
57
|
from fractal_server.app.schemas.user import UserCreate
|
63
58
|
from fractal_server.logger import get_logger
|
64
59
|
|
65
60
|
logger = get_logger(__name__)
|
66
61
|
|
62
|
+
FRACTAL_DEFAULT_GROUP_NAME = "All"
|
63
|
+
|
67
64
|
|
68
65
|
class SQLModelUserDatabaseAsync(Generic[UP, ID], BaseUserDatabase[UP, ID]):
|
69
66
|
"""
|
@@ -125,7 +122,7 @@ class SQLModelUserDatabaseAsync(Generic[UP, ID], BaseUserDatabase[UP, ID]):
|
|
125
122
|
return user
|
126
123
|
return None
|
127
124
|
|
128
|
-
async def create(self, create_dict:
|
125
|
+
async def create(self, create_dict: dict[str, Any]) -> UP:
|
129
126
|
"""Create a user."""
|
130
127
|
user = self.user_model(**create_dict)
|
131
128
|
self.session.add(user)
|
@@ -133,7 +130,7 @@ class SQLModelUserDatabaseAsync(Generic[UP, ID], BaseUserDatabase[UP, ID]):
|
|
133
130
|
await self.session.refresh(user)
|
134
131
|
return user
|
135
132
|
|
136
|
-
async def update(self, user: UP, update_dict:
|
133
|
+
async def update(self, user: UP, update_dict: dict[str, Any]) -> UP:
|
137
134
|
for key, value in update_dict.items():
|
138
135
|
setattr(user, key, value)
|
139
136
|
self.session.add(user)
|
@@ -146,7 +143,7 @@ class SQLModelUserDatabaseAsync(Generic[UP, ID], BaseUserDatabase[UP, ID]):
|
|
146
143
|
await self.session.commit()
|
147
144
|
|
148
145
|
async def add_oauth_account(
|
149
|
-
self, user: UP, create_dict:
|
146
|
+
self, user: UP, create_dict: dict[str, Any]
|
150
147
|
) -> UP: # noqa
|
151
148
|
if self.oauth_account_model is None:
|
152
149
|
raise NotImplementedError()
|
@@ -160,7 +157,7 @@ class SQLModelUserDatabaseAsync(Generic[UP, ID], BaseUserDatabase[UP, ID]):
|
|
160
157
|
return user
|
161
158
|
|
162
159
|
async def update_oauth_account(
|
163
|
-
self, user: UP, oauth_account: OAP, update_dict:
|
160
|
+
self, user: UP, oauth_account: OAP, update_dict: dict[str, Any]
|
164
161
|
) -> UP:
|
165
162
|
if self.oauth_account_model is None:
|
166
163
|
raise NotImplementedError()
|
@@ -176,13 +173,14 @@ class SQLModelUserDatabaseAsync(Generic[UP, ID], BaseUserDatabase[UP, ID]):
|
|
176
173
|
async def get_user_db(
|
177
174
|
session: AsyncSession = Depends(get_async_db),
|
178
175
|
) -> AsyncGenerator[SQLModelUserDatabaseAsync, None]:
|
179
|
-
yield SQLModelUserDatabaseAsync(session,
|
176
|
+
yield SQLModelUserDatabaseAsync(session, UserOAuth, OAuthAccount)
|
180
177
|
|
181
178
|
|
182
|
-
class UserManager(IntegerIDMixin, BaseUserManager[
|
183
|
-
async def validate_password(self, password: str, user:
|
179
|
+
class UserManager(IntegerIDMixin, BaseUserManager[UserOAuth, int]):
|
180
|
+
async def validate_password(self, password: str, user: UserOAuth) -> None:
|
184
181
|
# check password length
|
185
|
-
min_length
|
182
|
+
min_length = 4
|
183
|
+
max_length = 100
|
186
184
|
if len(password) < min_length:
|
187
185
|
raise InvalidPasswordException(
|
188
186
|
f"The password is too short (minimum length: {min_length})."
|
@@ -192,6 +190,38 @@ class UserManager(IntegerIDMixin, BaseUserManager[User, int]):
|
|
192
190
|
f"The password is too long (maximum length: {min_length})."
|
193
191
|
)
|
194
192
|
|
193
|
+
async def on_after_register(
|
194
|
+
self, user: UserOAuth, request: Optional[Request] = None
|
195
|
+
):
|
196
|
+
logger.info(
|
197
|
+
f"New-user registration completed ({user.id=}, {user.email=})."
|
198
|
+
)
|
199
|
+
async for db in get_async_db():
|
200
|
+
# Find default group
|
201
|
+
stm = select(UserGroup).where(
|
202
|
+
UserGroup.name == FRACTAL_DEFAULT_GROUP_NAME
|
203
|
+
)
|
204
|
+
res = await db.execute(stm)
|
205
|
+
default_group = res.scalar_one_or_none()
|
206
|
+
if default_group is None:
|
207
|
+
logger.error(
|
208
|
+
f"No group found with name {FRACTAL_DEFAULT_GROUP_NAME}"
|
209
|
+
)
|
210
|
+
else:
|
211
|
+
logger.warning(
|
212
|
+
f"START adding {user.email} user to group "
|
213
|
+
f"{default_group.id=}."
|
214
|
+
)
|
215
|
+
link = LinkUserGroup(
|
216
|
+
user_id=user.id, group_id=default_group.id
|
217
|
+
)
|
218
|
+
db.add(link)
|
219
|
+
await db.commit()
|
220
|
+
logger.warning(
|
221
|
+
f"END adding {user.email} user to group "
|
222
|
+
f"{default_group.id=}."
|
223
|
+
)
|
224
|
+
|
195
225
|
|
196
226
|
async def get_user_manager(
|
197
227
|
user_db: SQLModelUserDatabaseAsync = Depends(get_user_db),
|
@@ -199,53 +229,6 @@ async def get_user_manager(
|
|
199
229
|
yield UserManager(user_db)
|
200
230
|
|
201
231
|
|
202
|
-
bearer_transport = BearerTransport(tokenUrl="/auth/token/login")
|
203
|
-
cookie_transport = CookieTransport(cookie_samesite="none")
|
204
|
-
|
205
|
-
|
206
|
-
def get_jwt_strategy() -> JWTStrategy:
|
207
|
-
settings = Inject(get_settings)
|
208
|
-
return JWTStrategy(
|
209
|
-
secret=settings.JWT_SECRET_KEY, # type: ignore
|
210
|
-
lifetime_seconds=settings.JWT_EXPIRE_SECONDS,
|
211
|
-
)
|
212
|
-
|
213
|
-
|
214
|
-
def get_jwt_cookie_strategy() -> JWTStrategy:
|
215
|
-
settings = Inject(get_settings)
|
216
|
-
return JWTStrategy(
|
217
|
-
secret=settings.JWT_SECRET_KEY, # type: ignore
|
218
|
-
lifetime_seconds=settings.COOKIE_EXPIRE_SECONDS,
|
219
|
-
)
|
220
|
-
|
221
|
-
|
222
|
-
token_backend = AuthenticationBackend(
|
223
|
-
name="bearer-jwt",
|
224
|
-
transport=bearer_transport,
|
225
|
-
get_strategy=get_jwt_strategy,
|
226
|
-
)
|
227
|
-
cookie_backend = AuthenticationBackend(
|
228
|
-
name="cookie-jwt",
|
229
|
-
transport=cookie_transport,
|
230
|
-
get_strategy=get_jwt_cookie_strategy,
|
231
|
-
)
|
232
|
-
|
233
|
-
|
234
|
-
fastapi_users = FastAPIUsers[User, int](
|
235
|
-
get_user_manager,
|
236
|
-
[token_backend, cookie_backend],
|
237
|
-
)
|
238
|
-
|
239
|
-
|
240
|
-
# Create dependencies for users
|
241
|
-
current_active_user = fastapi_users.current_user(active=True)
|
242
|
-
current_active_verified_user = fastapi_users.current_user(
|
243
|
-
active=True, verified=True
|
244
|
-
)
|
245
|
-
current_active_superuser = fastapi_users.current_user(
|
246
|
-
active=True, superuser=True
|
247
|
-
)
|
248
|
-
|
249
232
|
get_async_session_context = contextlib.asynccontextmanager(get_async_db)
|
250
233
|
get_user_db_context = contextlib.asynccontextmanager(get_user_db)
|
251
234
|
get_user_manager_context = contextlib.asynccontextmanager(get_user_manager)
|
@@ -286,9 +269,9 @@ async def _create_first_user(
|
|
286
269
|
|
287
270
|
if is_superuser is True:
|
288
271
|
# If a superuser already exists, exit
|
289
|
-
stm = select(
|
290
|
-
|
291
|
-
)
|
272
|
+
stm = select(UserOAuth).where( # noqa
|
273
|
+
UserOAuth.is_superuser == True # noqa
|
274
|
+
) # noqa
|
292
275
|
res = await session.execute(stm)
|
293
276
|
existing_superuser = res.scalars().first()
|
294
277
|
if existing_superuser is not None:
|
@@ -311,11 +294,25 @@ async def _create_first_user(
|
|
311
294
|
user = await user_manager.create(UserCreate(**kwargs))
|
312
295
|
logger.info(f"User {user.email} created")
|
313
296
|
|
314
|
-
except IntegrityError:
|
315
|
-
logger.warning(
|
316
|
-
f"Creation of user {email} failed with IntegrityError "
|
317
|
-
"(likely due to concurrent attempts from different workers)."
|
318
|
-
)
|
319
|
-
|
320
297
|
except UserAlreadyExists:
|
321
298
|
logger.warning(f"User {email} already exists")
|
299
|
+
|
300
|
+
|
301
|
+
def _create_first_group():
|
302
|
+
logger.info(
|
303
|
+
f"START _create_first_group, with name {FRACTAL_DEFAULT_GROUP_NAME}"
|
304
|
+
)
|
305
|
+
with next(get_sync_db()) as db:
|
306
|
+
group_all = db.execute(select(UserGroup))
|
307
|
+
if group_all.scalars().one_or_none() is None:
|
308
|
+
first_group = UserGroup(name=FRACTAL_DEFAULT_GROUP_NAME)
|
309
|
+
db.add(first_group)
|
310
|
+
db.commit()
|
311
|
+
logger.info(f"Created group {FRACTAL_DEFAULT_GROUP_NAME}")
|
312
|
+
else:
|
313
|
+
logger.info(
|
314
|
+
f"Group {FRACTAL_DEFAULT_GROUP_NAME} already exists, skip."
|
315
|
+
)
|
316
|
+
logger.info(
|
317
|
+
f"END _create_first_group, with name {FRACTAL_DEFAULT_GROUP_NAME}"
|
318
|
+
)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
from packaging.version import parse
|
4
|
+
from sqlalchemy import select
|
5
|
+
|
6
|
+
import fractal_server
|
7
|
+
from fractal_server.app.db import get_sync_db
|
8
|
+
from fractal_server.app.models import LinkUserGroup
|
9
|
+
from fractal_server.app.models import UserGroup
|
10
|
+
from fractal_server.app.models import UserOAuth
|
11
|
+
from fractal_server.app.security import FRACTAL_DEFAULT_GROUP_NAME
|
12
|
+
|
13
|
+
|
14
|
+
def _check_current_version(*, expected_version: str):
|
15
|
+
# Check that this module matches with the current version
|
16
|
+
module_version = parse(expected_version)
|
17
|
+
current_version = parse(fractal_server.__VERSION__)
|
18
|
+
if (
|
19
|
+
current_version.major != module_version.major
|
20
|
+
or current_version.minor != module_version.minor
|
21
|
+
or current_version.micro != module_version.micro
|
22
|
+
):
|
23
|
+
raise RuntimeError(
|
24
|
+
f"{fractal_server.__VERSION__=} not matching with {__file__=}"
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
def fix_db():
|
29
|
+
logger = logging.getLogger("fix_db")
|
30
|
+
logger.warning("START execution of fix_db function")
|
31
|
+
_check_current_version(expected_version="2.4.0")
|
32
|
+
|
33
|
+
with next(get_sync_db()) as db:
|
34
|
+
# Find default group
|
35
|
+
stm = select(UserGroup).where(
|
36
|
+
UserGroup.name == FRACTAL_DEFAULT_GROUP_NAME
|
37
|
+
)
|
38
|
+
res = db.execute(stm)
|
39
|
+
default_group = res.scalar_one_or_none()
|
40
|
+
if default_group is None:
|
41
|
+
raise RuntimeError("Default group not found, exit.")
|
42
|
+
logger.warning(
|
43
|
+
"Default user group exists: "
|
44
|
+
f"{default_group.id=}, {default_group.name=}."
|
45
|
+
)
|
46
|
+
|
47
|
+
# Find
|
48
|
+
stm = select(UserOAuth)
|
49
|
+
users = db.execute(stm).scalars().unique().all()
|
50
|
+
for user in sorted(users, key=lambda x: x.id):
|
51
|
+
logger.warning(
|
52
|
+
f"START adding {user.id=} ({user.email=}) to default group."
|
53
|
+
)
|
54
|
+
link = LinkUserGroup(user_id=user.id, group_id=default_group.id)
|
55
|
+
db.add(link)
|
56
|
+
db.commit()
|
57
|
+
logger.warning(
|
58
|
+
f"END adding {user.id=} ({user.email=}) to default group."
|
59
|
+
)
|
60
|
+
|
61
|
+
logger.warning("END of execution of fix_db function")
|
fractal_server/main.py
CHANGED
@@ -22,7 +22,6 @@ from fastapi import FastAPI
|
|
22
22
|
|
23
23
|
from .app.routes.aux._runner import _backend_supports_shutdown # FIXME: change
|
24
24
|
from .app.runner.shutdown import cleanup_after_shutdown
|
25
|
-
from .app.security import _create_first_user
|
26
25
|
from .config import get_settings
|
27
26
|
from .logger import config_uvicorn_loggers
|
28
27
|
from .logger import get_logger
|
@@ -44,7 +43,7 @@ def collect_routers(app: FastAPI) -> None:
|
|
44
43
|
from .app.routes.api.v2 import router_api_v2
|
45
44
|
from .app.routes.admin.v1 import router_admin_v1
|
46
45
|
from .app.routes.admin.v2 import router_admin_v2
|
47
|
-
from .app.routes.auth import router_auth
|
46
|
+
from .app.routes.auth.router import router_auth
|
48
47
|
|
49
48
|
settings = Inject(get_settings)
|
50
49
|
|
@@ -91,13 +90,6 @@ async def lifespan(app: FastAPI):
|
|
91
90
|
logger.info("Start application startup")
|
92
91
|
check_settings()
|
93
92
|
settings = Inject(get_settings)
|
94
|
-
await _create_first_user(
|
95
|
-
email=settings.FRACTAL_DEFAULT_ADMIN_EMAIL,
|
96
|
-
password=settings.FRACTAL_DEFAULT_ADMIN_PASSWORD,
|
97
|
-
username=settings.FRACTAL_DEFAULT_ADMIN_USERNAME,
|
98
|
-
is_superuser=True,
|
99
|
-
is_verified=True,
|
100
|
-
)
|
101
93
|
|
102
94
|
if settings.FRACTAL_RUNNER_BACKEND == "slurm_ssh":
|
103
95
|
from fractal_server.ssh._fabric import get_ssh_connection
|
@@ -0,0 +1,53 @@
|
|
1
|
+
"""“Add_usergroup_and_linkusergroup_table”
|
2
|
+
|
3
|
+
Revision ID: 091b01f51f88
|
4
|
+
Revises: 5bf02391cfef
|
5
|
+
Create Date: 2024-09-09 13:17:51.008231
|
6
|
+
|
7
|
+
"""
|
8
|
+
import sqlalchemy as sa
|
9
|
+
import sqlmodel
|
10
|
+
from alembic import op
|
11
|
+
|
12
|
+
|
13
|
+
# revision identifiers, used by Alembic.
|
14
|
+
revision = "091b01f51f88"
|
15
|
+
down_revision = "5bf02391cfef"
|
16
|
+
branch_labels = None
|
17
|
+
depends_on = None
|
18
|
+
|
19
|
+
|
20
|
+
def upgrade() -> None:
|
21
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
22
|
+
op.create_table(
|
23
|
+
"usergroup",
|
24
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
25
|
+
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
|
26
|
+
sa.Column(
|
27
|
+
"timestamp_created", sa.DateTime(timezone=True), nullable=False
|
28
|
+
),
|
29
|
+
sa.PrimaryKeyConstraint("id"),
|
30
|
+
sa.UniqueConstraint("name"),
|
31
|
+
)
|
32
|
+
op.create_table(
|
33
|
+
"linkusergroup",
|
34
|
+
sa.Column("group_id", sa.Integer(), nullable=False),
|
35
|
+
sa.Column("user_id", sa.Integer(), nullable=False),
|
36
|
+
sa.ForeignKeyConstraint(
|
37
|
+
["group_id"],
|
38
|
+
["usergroup.id"],
|
39
|
+
),
|
40
|
+
sa.ForeignKeyConstraint(
|
41
|
+
["user_id"],
|
42
|
+
["user_oauth.id"],
|
43
|
+
),
|
44
|
+
sa.PrimaryKeyConstraint("group_id", "user_id"),
|
45
|
+
)
|
46
|
+
# ### end Alembic commands ###
|
47
|
+
|
48
|
+
|
49
|
+
def downgrade() -> None:
|
50
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
51
|
+
op.drop_table("linkusergroup")
|
52
|
+
op.drop_table("usergroup")
|
53
|
+
# ### end Alembic commands ###
|
@@ -1,15 +1,16 @@
|
|
1
|
-
fractal_server/__init__.py,sha256=
|
2
|
-
fractal_server/__main__.py,sha256=
|
1
|
+
fractal_server/__init__.py,sha256=pxca-5QdURrVFaaROnGdT3tkxUBWpx7_zq2uX-gI-b0,22
|
2
|
+
fractal_server/__main__.py,sha256=I9hF_SYc-GTZWDZZhihwyUBK7BMU5GAecbPLTjkpW4U,5830
|
3
3
|
fractal_server/alembic.ini,sha256=MWwi7GzjzawI9cCAK1LW7NxIBQDUqD12-ptJoq5JpP0,3153
|
4
4
|
fractal_server/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
fractal_server/app/db/__init__.py,sha256=KpS_mfmRfew0kieFDlwkSrDFvpzxftcvPALBBZ0LxsY,4048
|
6
|
-
fractal_server/app/models/__init__.py,sha256=
|
6
|
+
fractal_server/app/models/__init__.py,sha256=zt0Tiv91DWLg0daT8bkENz-LusihOJJX1h09UfHlAns,452
|
7
|
+
fractal_server/app/models/linkusergroup.py,sha256=ufthlbLFAWMU_dJmsVZzVlQa_D9C9SmgydxypQ2Xq1U,309
|
7
8
|
fractal_server/app/models/linkuserproject.py,sha256=eQaourbGRshvlMVlKzLYJKHEjfsW1CbWws9yW4eHXhA,567
|
8
|
-
fractal_server/app/models/security.py,sha256=
|
9
|
+
fractal_server/app/models/security.py,sha256=JGC3NNakIbJWhwksSIgJq0Jawo7m_fhsWX9L-uKpWJc,3551
|
9
10
|
fractal_server/app/models/v1/__init__.py,sha256=hUI7dEbPaiZGN0IbHW4RSmSicyvtn_xeuevoX7zvUwI,466
|
10
11
|
fractal_server/app/models/v1/dataset.py,sha256=99GDgt7njx8yYQApkImqp_7bHA5HH3ElvbR6Oyj9kVI,2017
|
11
12
|
fractal_server/app/models/v1/job.py,sha256=QLGXcWdVRHaUHQNDapYYlLpEfw4K7QyD8TmcwhrWw2o,3304
|
12
|
-
fractal_server/app/models/v1/project.py,sha256=
|
13
|
+
fractal_server/app/models/v1/project.py,sha256=JG7b5J9CzVNxua4MaMYpfB57xt2qjbXr5SnR7_oKQ70,819
|
13
14
|
fractal_server/app/models/v1/state.py,sha256=m9gMZqqnm3oDpJNJp-Lht4kM7oO7pcEI7sL1g7LFvWU,1043
|
14
15
|
fractal_server/app/models/v1/task.py,sha256=3xZqNeFYUqslh8ddMSXF2nO4nIiOD8T5Ij37wY20kss,2782
|
15
16
|
fractal_server/app/models/v1/workflow.py,sha256=dnY5eMaOe3oZv8arn00RNX9qVkBtTLG-vYdWXcQuyo4,3950
|
@@ -17,39 +18,48 @@ fractal_server/app/models/v2/__init__.py,sha256=uLzdInqATSwi0bS_V4vKB-TqFrOFaXux
|
|
17
18
|
fractal_server/app/models/v2/collection_state.py,sha256=nxb042i8tt8rCpmgbFJoBCYWU-34m0HdUfO9YurTp8k,588
|
18
19
|
fractal_server/app/models/v2/dataset.py,sha256=-7sxHEw4IIAvF_uSan7tA3o8hvoakBkQ0SRvqS2iOQU,1455
|
19
20
|
fractal_server/app/models/v2/job.py,sha256=ypJmN-qspkKBGhBG7Mt-HypSQqcQ2EmB4Bzzb2-y550,1535
|
20
|
-
fractal_server/app/models/v2/project.py,sha256=
|
21
|
+
fractal_server/app/models/v2/project.py,sha256=rAHoh5KfYwIaW7rTX0_O0jvWmxEvfo1BafvmcXuSSRk,786
|
21
22
|
fractal_server/app/models/v2/task.py,sha256=Esf2j9c-0pGYjdbb__Ptpdx7NCAKVxqbQMoza524miU,1286
|
22
23
|
fractal_server/app/models/v2/workflow.py,sha256=YBgFGCziUgU0aJ5EM3Svu9W2c46AewZO9VBlFCHiSps,1069
|
23
24
|
fractal_server/app/models/v2/workflowtask.py,sha256=3jEkObsSnlI05Pur_dSsXYdJxRqPL60Z7tK5-EJLOks,1532
|
24
25
|
fractal_server/app/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
26
|
fractal_server/app/routes/admin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
|
-
fractal_server/app/routes/admin/v1.py,sha256=
|
27
|
-
fractal_server/app/routes/admin/v2.py,sha256=
|
28
|
-
fractal_server/app/routes/api/__init__.py,sha256=
|
27
|
+
fractal_server/app/routes/admin/v1.py,sha256=GIpZlwAwwwLGDWkBqywhtmp9TGsKLhGmZAdj1TDKJvE,13976
|
28
|
+
fractal_server/app/routes/admin/v2.py,sha256=P6ndmwNYfXDW5Xh971hMcmlVyVrGF8ubYS074r4bzok,13727
|
29
|
+
fractal_server/app/routes/api/__init__.py,sha256=2IDheFi0OFdsUg7nbUiyahqybvpgXqeHUXIL2QtWrQQ,641
|
29
30
|
fractal_server/app/routes/api/v1/__init__.py,sha256=Y2HQdG197J0a7DyQEE2jn53IfxD0EHGhzK1I2JZuEck,958
|
30
|
-
fractal_server/app/routes/api/v1/_aux_functions.py,sha256=
|
31
|
-
fractal_server/app/routes/api/v1/dataset.py,sha256=
|
32
|
-
fractal_server/app/routes/api/v1/job.py,sha256=
|
33
|
-
fractal_server/app/routes/api/v1/project.py,sha256=
|
34
|
-
fractal_server/app/routes/api/v1/task.py,sha256
|
35
|
-
fractal_server/app/routes/api/v1/task_collection.py,sha256=
|
36
|
-
fractal_server/app/routes/api/v1/workflow.py,sha256=
|
37
|
-
fractal_server/app/routes/api/v1/workflowtask.py,sha256=
|
31
|
+
fractal_server/app/routes/api/v1/_aux_functions.py,sha256=1YZdLch-Q1c44hQ_1ZEiijgWhLW6H3QEL5y5SHw5Ijk,13023
|
32
|
+
fractal_server/app/routes/api/v1/dataset.py,sha256=KVfKdp-bT8eB14kCjTSmpji4a2IPIHxGID8L10h3Wac,17282
|
33
|
+
fractal_server/app/routes/api/v1/job.py,sha256=0jGxvu0xNQnWuov2qnoo9yE7Oat37XbcVn4Ute-UsiE,5370
|
34
|
+
fractal_server/app/routes/api/v1/project.py,sha256=mFDqhkd_zR3wqxW5zadCCrxIX-jgL3lYF3CtfbV4pPs,16373
|
35
|
+
fractal_server/app/routes/api/v1/task.py,sha256=OLASM6M4yfHvQgHQOuR5810jR2s0_W1HQAmhGQkg0so,6356
|
36
|
+
fractal_server/app/routes/api/v1/task_collection.py,sha256=VYxhtd_idBppgJM7-FCHikI2OKMAIz05fhV_TsJpWI8,9060
|
37
|
+
fractal_server/app/routes/api/v1/workflow.py,sha256=2T93DuEnSshaDCue-JPmjuvGCtbk6lt9pFMuPt783t8,11217
|
38
|
+
fractal_server/app/routes/api/v1/workflowtask.py,sha256=OYYConwJbmNULDw5I3T-UbSJKrbbBiAHbbBeVcpoFKQ,5785
|
38
39
|
fractal_server/app/routes/api/v2/__init__.py,sha256=JrPWfKIJy9btRCP-zw2nZwLpSdBxEKY5emuCuJbqG0s,1813
|
39
|
-
fractal_server/app/routes/api/v2/_aux_functions.py,sha256=
|
40
|
-
fractal_server/app/routes/api/v2/dataset.py,sha256=
|
41
|
-
fractal_server/app/routes/api/v2/images.py,sha256=
|
42
|
-
fractal_server/app/routes/api/v2/job.py,sha256=
|
43
|
-
fractal_server/app/routes/api/v2/project.py,sha256=
|
44
|
-
fractal_server/app/routes/api/v2/status.py,sha256=
|
45
|
-
fractal_server/app/routes/api/v2/submit.py,sha256=
|
46
|
-
fractal_server/app/routes/api/v2/task.py,sha256=
|
47
|
-
fractal_server/app/routes/api/v2/task_collection.py,sha256=
|
48
|
-
fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=
|
49
|
-
fractal_server/app/routes/api/v2/task_legacy.py,sha256=
|
50
|
-
fractal_server/app/routes/api/v2/workflow.py,sha256=
|
51
|
-
fractal_server/app/routes/api/v2/workflowtask.py,sha256=
|
52
|
-
fractal_server/app/routes/auth.py,sha256=
|
40
|
+
fractal_server/app/routes/api/v2/_aux_functions.py,sha256=sm__AJvEQfRYlh47uYMJ7PjSrmwz5LjjZMTcJdvhuVE,14924
|
41
|
+
fractal_server/app/routes/api/v2/dataset.py,sha256=Eilf_BAGjicIhqUiVwI86jlW45ineA5sVzxXW4b2GoQ,8329
|
42
|
+
fractal_server/app/routes/api/v2/images.py,sha256=JR1rR6qEs81nacjriOXAOBQjAbCXF4Ew7M7mkWdxBU0,7920
|
43
|
+
fractal_server/app/routes/api/v2/job.py,sha256=Bga2Kz1OjvDIdxZObWaaXVhNIhC_5JKhKRjEH2_ayEE,5157
|
44
|
+
fractal_server/app/routes/api/v2/project.py,sha256=eWYFJ7F2ZYQcpi-_n-rhPF-Q4gJhzYBsVGYFhHZZXAE,6653
|
45
|
+
fractal_server/app/routes/api/v2/status.py,sha256=6N9DSZ4iFqbZImorWfEAPoyoFUgEruo4Hweqo0x0xXU,6435
|
46
|
+
fractal_server/app/routes/api/v2/submit.py,sha256=iTGCYbxiZNszHQa8r3gmAR4QcF6QhVrb8ktzste2Ovc,8775
|
47
|
+
fractal_server/app/routes/api/v2/task.py,sha256=XgRnGBvSoI9VNJHtWZQ2Ide99f6elo7a2FN3GQkf0dU,8376
|
48
|
+
fractal_server/app/routes/api/v2/task_collection.py,sha256=wEwP8VfsxhKPZ6K3v1Bnput_Zw0Cjhlaal0-e50feIQ,12337
|
49
|
+
fractal_server/app/routes/api/v2/task_collection_custom.py,sha256=6MW-l7xTCTbWKDSYDw8e_hnm5jFCJpgFL3UdvrHAaBk,6029
|
50
|
+
fractal_server/app/routes/api/v2/task_legacy.py,sha256=GjW0lpX51b64-LCg2EtCO3Ik6Yx4eTqgbtspXh-K_4k,1744
|
51
|
+
fractal_server/app/routes/api/v2/workflow.py,sha256=8rir-alW5KjS6_HIkYFPkJcm3BouAFsKboKqGu8HSqo,11944
|
52
|
+
fractal_server/app/routes/api/v2/workflowtask.py,sha256=HoHFnVRDa0Cw1oqTea1Of6A5ZhjGJeSTDTdI-SKP7Co,8063
|
53
|
+
fractal_server/app/routes/auth/__init__.py,sha256=fao6CS0WiAjHDTvBzgBVV_bSXFpEAeDBF6Z6q7rRkPc,1658
|
54
|
+
fractal_server/app/routes/auth/_aux_auth.py,sha256=Kpgiw5q1eiCYLFkfhTT7XJGBu1d08YM71CEHhNtfJ5g,3126
|
55
|
+
fractal_server/app/routes/auth/current_user.py,sha256=LK0Z13NgaXYQ3FaQ3MNec0p2RRiKxKN31XIt2g9mcGk,2003
|
56
|
+
fractal_server/app/routes/auth/group.py,sha256=az8kRJJU5rA0L8GCX5kvRNuQhrsoGWPuvQ26z7iFQ3E,5388
|
57
|
+
fractal_server/app/routes/auth/group_names.py,sha256=zvYDfhxKlDmbSr-oLXYy6WUVkPPTvzH6ZJtuoNdGZbE,960
|
58
|
+
fractal_server/app/routes/auth/login.py,sha256=tSu6OBLOieoBtMZB4JkBAdEgH2Y8KqPGSbwy7NIypIo,566
|
59
|
+
fractal_server/app/routes/auth/oauth.py,sha256=AnFHbjqL2AgBX3eksI931xD6RTtmbciHBEuGf9YJLjU,1895
|
60
|
+
fractal_server/app/routes/auth/register.py,sha256=DlHq79iOvGd_gt2v9uwtsqIKeO6i_GKaW59VIkllPqY,587
|
61
|
+
fractal_server/app/routes/auth/router.py,sha256=zWoZWiO69U48QFQf5tLRYQDWu8PUCj7GacnaFeW1n_I,618
|
62
|
+
fractal_server/app/routes/auth/users.py,sha256=hNTIR0e3QFbUUDvkzKNXJt4uKwONlI36i6UjjMPCgAA,6672
|
53
63
|
fractal_server/app/routes/aux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
64
|
fractal_server/app/routes/aux/_job.py,sha256=q-RCiW17yXnZKAC_0La52RLvhqhxuvbgQJ2MlGXOj8A,702
|
55
65
|
fractal_server/app/routes/aux/_runner.py,sha256=FdCVla5DxGAZ__aB7Z8dEJzD_RIeh5tftjrPyqkr8N8,895
|
@@ -90,7 +100,7 @@ fractal_server/app/runner/v1/_slurm/_submit_setup.py,sha256=KO9c694d318adoPQh9UG
|
|
90
100
|
fractal_server/app/runner/v1/_slurm/get_slurm_config.py,sha256=6pQNNx997bLIfLp0guF09t_O0ZYRXnbEGLktSAcKnic,5999
|
91
101
|
fractal_server/app/runner/v1/common.py,sha256=_L-vjLnWato80VdlB_BFN4G8P4jSM07u-5cnl1T3S34,3294
|
92
102
|
fractal_server/app/runner/v1/handle_failed_job.py,sha256=bHzScC_aIlU3q-bQxGW6rfWV4xbZ2tho_sktjsAs1no,4684
|
93
|
-
fractal_server/app/runner/v2/__init__.py,sha256=
|
103
|
+
fractal_server/app/runner/v2/__init__.py,sha256=gEof2P2PApNM4Ubc8JQg6NEBA8ej55Ar15YMWEdXdgA,17176
|
94
104
|
fractal_server/app/runner/v2/_local/__init__.py,sha256=KTj14K6jH8fXGUi5P7u5_RqEE1zF4aXtgPxCKzw46iw,5971
|
95
105
|
fractal_server/app/runner/v2/_local/_local_config.py,sha256=9oi209Dlp35ANfxb_DISqmMKKc6DPaMsmYVWbZLseME,3630
|
96
106
|
fractal_server/app/runner/v2/_local/_submit_setup.py,sha256=MucNOo8Er0F5ZIwH7CnTeXgnFMc6d3pKPkv563QNVi0,1630
|
@@ -101,7 +111,7 @@ fractal_server/app/runner/v2/_local_experimental/_submit_setup.py,sha256=we7r-sQ
|
|
101
111
|
fractal_server/app/runner/v2/_local_experimental/executor.py,sha256=vcBKjireIIyF5WgIQLatD6ojlWEydbTwyIG0bcpIjys,5438
|
102
112
|
fractal_server/app/runner/v2/_slurm_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
103
113
|
fractal_server/app/runner/v2/_slurm_common/get_slurm_config.py,sha256=V47uckqA4Vp-7m5esDnTitekc-yabLhaZSlPj4jN_D8,6307
|
104
|
-
fractal_server/app/runner/v2/_slurm_ssh/__init__.py,sha256=
|
114
|
+
fractal_server/app/runner/v2/_slurm_ssh/__init__.py,sha256=D0Dnbhnzw0BXwQmjqLmxqpE9oreAtasA-9aOzxC4l_I,4530
|
105
115
|
fractal_server/app/runner/v2/_slurm_ssh/_submit_setup.py,sha256=a5_FDPH_yxYmrjAjMRLgh_Y4DSG3mRslCLQodGM3-t4,2838
|
106
116
|
fractal_server/app/runner/v2/_slurm_sudo/__init__.py,sha256=q2fwiKqtNpXtfs5wUFQjwJxdYqKPPTbCy1ieBhhi-Bw,4316
|
107
117
|
fractal_server/app/runner/v2/_slurm_sudo/_submit_setup.py,sha256=a5_FDPH_yxYmrjAjMRLgh_Y4DSG3mRslCLQodGM3-t4,2838
|
@@ -116,7 +126,8 @@ fractal_server/app/runner/v2/v1_compat.py,sha256=t0ficzAHUFaaeI56nqTb4YEKxfARF7L
|
|
116
126
|
fractal_server/app/runner/versions.py,sha256=dSaPRWqmFPHjg20kTCHmi_dmGNcCETflDtDLronNanU,852
|
117
127
|
fractal_server/app/schemas/__init__.py,sha256=jiIf54owztXupv3PO6Ilh0qcrkh2RUzKq4bcEFqEfc4,40
|
118
128
|
fractal_server/app/schemas/_validators.py,sha256=1dTOYr1IZykrxuQSV2-zuEMZbKe_nGwrfS7iUrsh-sE,3461
|
119
|
-
fractal_server/app/schemas/user.py,sha256=
|
129
|
+
fractal_server/app/schemas/user.py,sha256=jRMUd3v7kmnOdHhGSoljKbCk6xyaJuGHRXkaxAxI8RA,3437
|
130
|
+
fractal_server/app/schemas/user_group.py,sha256=2f9XQ6kIar6NMY4UCN0yOnve6ZDHUVZaHv1dna1Vfjg,1446
|
120
131
|
fractal_server/app/schemas/v1/__init__.py,sha256=CrBGgBhoemCvmZ70ZUchM-jfVAICnoa7AjZBAtL2UB0,1852
|
121
132
|
fractal_server/app/schemas/v1/applyworkflow.py,sha256=uuIh7fHlHEL4yLqL-dePI6-nfCsqgBYATmht7w_KITw,4302
|
122
133
|
fractal_server/app/schemas/v1/dataset.py,sha256=n71lNUO3JLy2K3IM9BZM2Fk1EnKQOTU7pm2s2rJ1FGY,3444
|
@@ -138,18 +149,20 @@ fractal_server/app/schemas/v2/task.py,sha256=7IfxiZkaVqlARy7WYE_H8m7j_IEcuQaZORU
|
|
138
149
|
fractal_server/app/schemas/v2/task_collection.py,sha256=8PG1bOqkfQqORMN0brWf6mHDmijt0bBW-mZsF7cSxUs,6129
|
139
150
|
fractal_server/app/schemas/v2/workflow.py,sha256=Zzx3e-qgkH8le0FUmAx9UrV5PWd7bj14PPXUh_zgZXM,1827
|
140
151
|
fractal_server/app/schemas/v2/workflowtask.py,sha256=atVuVN4aXsVEOmSd-vyg-8_8OnPmqx-gT75rXcn_AlQ,6552
|
141
|
-
fractal_server/app/security/__init__.py,sha256=
|
152
|
+
fractal_server/app/security/__init__.py,sha256=FBxdrMvn2s3Gdmp1orqOpYji87JojLBzr9TMfblj1SI,11441
|
142
153
|
fractal_server/config.py,sha256=R0VezSe2PEDjQjHEX2V29A1jMdoomdyECBjWNY15v_0,25049
|
154
|
+
fractal_server/data_migrations/2_4_0.py,sha256=T1HRRWp9ZuXeVfBY6NRGxQ8aNIHVSftOMnB-CMrfvi8,2117
|
143
155
|
fractal_server/data_migrations/README.md,sha256=_3AEFvDg9YkybDqCLlFPdDmGJvr6Tw7HRI14aZ3LOIw,398
|
144
156
|
fractal_server/gunicorn_fractal.py,sha256=u6U01TLGlXgq1v8QmEpLih3QnsInZD7CqphgJ_GrGzc,1230
|
145
157
|
fractal_server/images/__init__.py,sha256=xO6jTLE4EZKO6cTDdJsBmK9cdeh9hFTaSbSuWgQg7y4,196
|
146
158
|
fractal_server/images/models.py,sha256=9ipU5h4N6ogBChoB-2vHoqtL0TXOHCv6kRR-fER3mkM,4167
|
147
159
|
fractal_server/images/tools.py,sha256=gxeniYy4Z-cp_ToK2LHPJUTVVUUrdpogYdcBUvBuLiY,2209
|
148
160
|
fractal_server/logger.py,sha256=56wfka6fHaa3Rx5qO009nEs_y8gx5wZ2NUNZZ1I-uvc,5130
|
149
|
-
fractal_server/main.py,sha256=
|
161
|
+
fractal_server/main.py,sha256=NUvMd8C8kosulAcQ8pCFLnOGdLw7j-6RzcHxoNvSB7k,5003
|
150
162
|
fractal_server/migrations/README,sha256=4rQvyDfqodGhpJw74VYijRmgFP49ji5chyEemWGHsuw,59
|
151
163
|
fractal_server/migrations/env.py,sha256=Bvg-FJzRJZIH_wqS_ZyZNXANIaathjo22_IY7c3fCjo,2636
|
152
164
|
fractal_server/migrations/script.py.mako,sha256=oMXw9LC3zRbinWWPPDgeZ4z9FJrV2zhRWiYdS5YgNbI,526
|
165
|
+
fractal_server/migrations/versions/091b01f51f88_add_usergroup_and_linkusergroup_table.py,sha256=BtcSkXsY7ZHNmwV93bSTiDw-wuxpfL7xpbZ5zH-nLnA,1456
|
153
166
|
fractal_server/migrations/versions/4c308bcaea2b_add_task_args_schema_and_task_args_.py,sha256=-wHe-fOffmYeAm0JXVl_lxZ7hhDkaEVqxgxpHkb_uL8,954
|
154
167
|
fractal_server/migrations/versions/4cedeb448a53_workflowtask_foreign_keys_not_nullables.py,sha256=Mob8McGYAcmgvrseyyYOa54E6Gsgr-4SiGdC-r9O4_A,1157
|
155
168
|
fractal_server/migrations/versions/50a13d6138fd_initial_schema.py,sha256=zwXegXs9J40eyCWi3w0c_iIBVJjXNn4VdVnQaT3KxDg,8770
|
@@ -194,8 +207,8 @@ fractal_server/tasks/v2/utils.py,sha256=JOyCacb6MNvrwfLNTyLwcz8y79J29YuJeJ2MK5kq
|
|
194
207
|
fractal_server/urls.py,sha256=5o_qq7PzKKbwq12NHSQZDmDitn5RAOeQ4xufu-2v9Zk,448
|
195
208
|
fractal_server/utils.py,sha256=b7WwFdcFZ8unyT65mloFToYuEDXpQoHRcmRNqrhd_dQ,2115
|
196
209
|
fractal_server/zip_tools.py,sha256=xYpzBshysD2nmxkD5WLYqMzPYUcCRM3kYy-7n9bJL-U,4426
|
197
|
-
fractal_server-2.
|
198
|
-
fractal_server-2.
|
199
|
-
fractal_server-2.
|
200
|
-
fractal_server-2.
|
201
|
-
fractal_server-2.
|
210
|
+
fractal_server-2.4.0.dist-info/LICENSE,sha256=QKAharUuhxL58kSoLizKJeZE3mTCBnX6ucmz8W0lxlk,1576
|
211
|
+
fractal_server-2.4.0.dist-info/METADATA,sha256=iBNotVuDgKZmNmaiJb2sEKTYEUe0T4vLuE2iQZXHcYY,4628
|
212
|
+
fractal_server-2.4.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
213
|
+
fractal_server-2.4.0.dist-info/entry_points.txt,sha256=8tV2kynvFkjnhbtDnxAqImL6HMVKsopgGfew0DOp5UY,58
|
214
|
+
fractal_server-2.4.0.dist-info/RECORD,,
|