Source code for datamasque.client.users
from typing import Optional
from datamasque.client.base import BaseClient
from datamasque.client.exceptions import DataMasqueException, DataMasqueUserError
from datamasque.client.models.user import User, UserId, UserRole
[docs]
class UserClient(BaseClient):
"""User CRUD API methods. Mixed into `DataMasqueClient`."""
[docs]
def list_users(self) -> list[User]:
"""Returns all active users configured on the server."""
users = []
for user_data in self.make_request("GET", "/api/users/").json():
if user_data.get("is_active", False):
users.append(User.model_validate(user_data))
return users
[docs]
def create_or_update_user(self, user: User, new_password: Optional[str] = None) -> User:
"""
Creates or updates the user.
An update will be performed if `user.id` is set, otherwise a create.
To also set the user's password,
put the old password in the user's `password` field (for an existing user)
and pass the new password in the `new_password` parameter.
Returns the same User object but with the id and password fields populated.
"""
if not user.roles:
raise DataMasqueUserError("User must have at least one role")
if UserRole.ruleset_library_manager in user.roles and UserRole.mask_builder not in user.roles:
raise DataMasqueUserError("`ruleset_library_manager` role requires `mask_builder` role")
if user.id is None:
temp_password = User.generate_password()
data = user.model_dump(exclude_none=True, by_alias=True, mode="json") | {
"password": temp_password,
"re_password": temp_password,
}
resp = self.make_request("POST", "/api/users/", data=data).json()
user.id = resp["id"]
user.password = temp_password
else:
self.make_request(
"PATCH",
f"/api/users/{user.id}/",
data=user.model_dump(exclude_none=True, by_alias=True, mode="json"),
).json()
if new_password:
self.make_request(
"PATCH",
f"/api/users/{user.id}/",
data={
"current_password": user.password,
"new_password": new_password,
"re_new_password": new_password,
},
)
user.password = new_password
return user
[docs]
def reset_password_for_user(self, user: User) -> str:
"""
Resets the user's password.
The temporary password is stored on the User object and also returned.
"""
if user.id is None:
raise DataMasqueUserError("User must be created first")
resp = self.make_request("POST", f"/api/users/{user.id}/reset-password/").json()
user.password = resp["password"]
return user.password
[docs]
def delete_user_by_id_if_exists(self, user_id: UserId) -> None:
"""Deletes the user with the given ID. No-op if the user does not exist."""
self._delete_if_exists(f"/api/users/{user_id}/")
[docs]
def delete_user_by_username_if_exists(self, username: str) -> None:
"""Deletes the user with the given username. No-op if the user does not exist."""
all_users = self.list_users()
users_matching_username = [u for u in all_users if u.username == username]
for user in users_matching_username:
if user.id is None:
raise DataMasqueException(f'Server returned a user named "{user.username}" without an `id`.')
self.delete_user_by_id_if_exists(user.id)