diff --git a/fractal_server/app/models/security.py b/fractal_server/app/models/security.py index 2e002a0827..e6615dc59f 100644 --- a/fractal_server/app/models/security.py +++ b/fractal_server/app/models/security.py @@ -110,7 +110,7 @@ class UserOAuth(SQLModel, table=True): foreign_key="user_settings.id", default=None ) settings: Optional[UserSettings] = Relationship( - sa_relationship_kwargs=dict(lazy="selectin") + sa_relationship_kwargs=dict(lazy="selectin", cascade="all, delete") ) class Config: diff --git a/fractal_server/app/routes/aux/validate_user_settings.py b/fractal_server/app/routes/aux/validate_user_settings.py index b45e8ad531..ac2c9badf6 100644 --- a/fractal_server/app/routes/aux/validate_user_settings.py +++ b/fractal_server/app/routes/aux/validate_user_settings.py @@ -6,9 +6,9 @@ from fractal_server.app.db import AsyncSession from fractal_server.app.models import UserOAuth from fractal_server.app.models import UserSettings +from fractal_server.app.user_settings import SlurmSshUserSettings +from fractal_server.app.user_settings import SlurmSudoUserSettings from fractal_server.logger import set_logger -from fractal_server.user_settings import SlurmSshUserSettings -from fractal_server.user_settings import SlurmSudoUserSettings logger = set_logger(__name__) diff --git a/fractal_server/app/schemas/user_settings.py b/fractal_server/app/schemas/user_settings.py index 2c713124a9..00bb5cecdb 100644 --- a/fractal_server/app/schemas/user_settings.py +++ b/fractal_server/app/schemas/user_settings.py @@ -63,9 +63,14 @@ class UserSettingsUpdate(BaseModel): _slurm_user = validator("slurm_user", allow_reuse=True)( valstr("slurm_user") ) - _slurm_accounts = validator("slurm_accounts", allow_reuse=True)( - val_unique_list("slurm_accounts") - ) + + @validator("slurm_accounts") + def slurm_accounts_validator(cls, value): + if value is None: + return value + for i, item in enumerate(value): + value[i] = valstr(f"slurm_accounts[{i}]")(item) + return val_unique_list("slurm_accounts")(value) @validator("cache_dir") def cache_dir_validator(cls, value): diff --git a/fractal_server/user_settings.py b/fractal_server/app/user_settings.py similarity index 97% rename from fractal_server/user_settings.py rename to fractal_server/app/user_settings.py index 841e4ebef6..786dce7af3 100644 --- a/fractal_server/user_settings.py +++ b/fractal_server/app/user_settings.py @@ -20,6 +20,7 @@ class SlurmSshUserSettings(BaseModel): ssh_private_key_path: str ssh_tasks_dir: str ssh_jobs_dir: str + slurm_accounts: list[str] class SlurmSudoUserSettings(BaseModel): diff --git a/tests/no_version/test_auth_api.py b/tests/no_version/test_auth_api.py index 65b91c2a03..d96c7ee20e 100644 --- a/tests/no_version/test_auth_api.py +++ b/tests/no_version/test_auth_api.py @@ -562,7 +562,7 @@ async def test_get_and_patch_user_settings(registered_superuser_client): ssh_private_key_path="/tmp/fractal", ssh_tasks_dir="/tmp/tasks", # missing "ssh_jobs_dir" - # missing "slurm_user" + slurm_user="fractal", slurm_accounts=["foo", "bar"], cache_dir="/tmp/cache", ) @@ -572,6 +572,12 @@ async def test_get_and_patch_user_settings(registered_superuser_client): debug(res.json()) assert res.status_code == 200 + res = await registered_superuser_client.patch( + f"{PREFIX}/users/{user_id}/settings/", json=dict(slurm_accounts=[" "]) + ) + debug(res.json()) + assert res.status_code == 422 + # Assert patch was successful res = await registered_superuser_client.get( f"{PREFIX}/users/{user_id}/settings/", diff --git a/tests/no_version/test_delete_user.py b/tests/no_version/test_delete_user.py index bb87baee9f..a92034bc4b 100644 --- a/tests/no_version/test_delete_user.py +++ b/tests/no_version/test_delete_user.py @@ -2,6 +2,7 @@ from sqlmodel import select from fractal_server.app.models.security import UserOAuth +from fractal_server.app.models.security import UserSettings from fractal_server.app.models.v1 import LinkUserProject from fractal_server.app.models.v2 import LinkUserProjectV2 @@ -54,3 +55,33 @@ async def test_delete_user( assert len(project_v2.user_list) == 0 assert len(project_v1_2.user_list) == 1 assert len(project_v2_2.user_list) == 1 + + +async def test_cascade_on_delete_user_settings(db): + + user = UserOAuth( + email="user@fractal.xy", + hashed_password="fake_hashed_password", + settings=UserSettings(slurm_accounts=["account1", "account2"]), + ) + db.add(user) + await db.commit() + + await db.refresh(user) + user_id = user.id + user_settings_id = user.user_settings_id + + await db.close() + + user = await db.get(UserOAuth, user_id) + assert user is not None + user_settings = await db.get(UserSettings, user_settings_id) + assert user_settings is not None + + await db.delete(user) + await db.commit() + + user = await db.get(UserOAuth, user_id) + assert user is None + user_settings = await db.get(UserSettings, user_settings_id) + assert user_settings is None