Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce PATCH user settings bulk-endpoint for user group #1936

Merged
merged 9 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ into pre-release sections below.

* API
* Improve error messages from task collection (\#1913).
* Add `PATCH auth/group/{group_id}/user-settings/` bulk endpoint (\#1936).
* Database:
* Verify task-group non-duplication constraint in `2.7.0` data-migration script (\#1927).
* Normalize pkg_name in `2.7.0` data-migration script (\#1930).
Expand Down
27 changes: 27 additions & 0 deletions fractal_server/app/routes/auth/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
from fractal_server.app.models import LinkUserGroup
from fractal_server.app.models import UserGroup
from fractal_server.app.models import UserOAuth
from fractal_server.app.models import UserSettings
from fractal_server.app.models.v2 import TaskGroupV2
from fractal_server.app.schemas.user_group import UserGroupCreate
from fractal_server.app.schemas.user_group import UserGroupRead
from fractal_server.app.schemas.user_group import UserGroupUpdate
from fractal_server.app.schemas.user_settings import UserSettingsUpdate
from fractal_server.app.security import FRACTAL_DEFAULT_GROUP_NAME
from fractal_server.logger import set_logger

Expand Down Expand Up @@ -212,3 +214,28 @@ async def delete_single_group(
await db.commit()

return Response(status_code=status.HTTP_204_NO_CONTENT)


@router_group.patch("/group/{group_id}/user-settings/", status_code=200)
async def patch_user_settings_bulk(
group_id: int,
settings_update: UserSettingsUpdate,
superuser: UserOAuth = Depends(current_active_superuser),
db: AsyncSession = Depends(get_async_db),
):
await _usergroup_or_404(group_id, db)
res = await db.execute(
select(UserSettings)
.join(UserOAuth)
.where(LinkUserGroup.user_id == UserOAuth.id)
.where(LinkUserGroup.group_id == group_id)
)
settings_list = res.scalars().all()
update = settings_update.dict(exclude_unset=True)
for settings in settings_list:
for k, v in update.items():
setattr(settings, k, v)
db.add(settings)
await db.commit()

return Response(status_code=status.HTTP_200_OK)
75 changes: 75 additions & 0 deletions tests/no_version/test_api_user_groups.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from sqlmodel import select

from fractal_server.app.models import LinkUserGroup
from fractal_server.app.models import UserOAuth
from fractal_server.app.models.v2 import TaskGroupV2

PREFIX = "/auth"
Expand Down Expand Up @@ -299,3 +300,77 @@ async def test_get_user_optional_group_info(
assert res.status_code == 200
user = res.json()
assert user["group_ids_names"] == expected_attribute


async def test_patch_user_settings_bulk(
MockCurrentUser, registered_superuser_client, default_user_group, db
):

# Register 4 users
async with MockCurrentUser() as user1:
pass
async with MockCurrentUser() as user2:
pass
async with MockCurrentUser() as user3:
pass
async with MockCurrentUser() as user4:
pass

user1 = await db.get(UserOAuth, user1.id)
user2 = await db.get(UserOAuth, user2.id)
user3 = await db.get(UserOAuth, user3.id)
user4 = await db.get(UserOAuth, user4.id)

for user in [user1, user2, user3, user4]:
assert dict(
ssh_host=None,
ssh_username=None,
ssh_private_key_path=None,
ssh_tasks_dir=None,
ssh_jobs_dir=None,
slurm_user="test01",
slurm_accounts=[],
cache_dir=None,
) == user.settings.dict(exclude={"id"})

# remove user4 from default user group
res = await db.execute(
select(LinkUserGroup).where(LinkUserGroup.user_id == user4.id)
)
link = res.scalars().one()
await db.delete(link)
await db.commit()

# patch user-settings of default user group
patch = dict(
ssh_host="127.0.0.1",
ssh_username="fractal",
ssh_private_key_path="/tmp/fractal",
ssh_tasks_dir="/tmp/tasks",
ssh_jobs_dir="/tmp/job",
# missing `slurm_user`
slurm_accounts=["foo", "bar"],
cache_dir="/tmp/cache",
)
res = await registered_superuser_client.patch(
f"{PREFIX}/group/{default_user_group.id}/user-settings/", json=patch
)
assert res.status_code == 200

# assert user1, user2 and user3 has been updated
for user in [user1, user2, user3]:
await db.refresh(user)
assert patch == user.settings.dict(exclude={"id", "slurm_user"})
assert user.settings.slurm_user == "test01" # `slurm_user` not patched
# assert user4 has old settings
await db.refresh(user4)
assert dict(
ssh_host=None,
ssh_username=None,
ssh_private_key_path=None,
ssh_tasks_dir=None,
ssh_jobs_dir=None,
slurm_user="test01",
slurm_accounts=[],
cache_dir=None,
) == user4.settings.dict(exclude={"id"})