Skip to content

Async Security

AsyncSecurityNamespace for security group management and service account utilities, accessed as client.security on AsyncOdooClient.

security

Async security group utilities for Vodoo.

AsyncSecurityNamespace

AsyncSecurityNamespace(client: AsyncOdooClient)

Async security group operations namespace.

Source code in src/vodoo/aio/security.py
def __init__(self, client: AsyncOdooClient) -> None:
    self._client = client

create_groups async

create_groups() -> tuple[dict[str, int], list[str]]

Create (or reuse) all Vodoo security groups.

Source code in src/vodoo/aio/security.py
async def create_groups(self) -> tuple[dict[str, int], list[str]]:
    """Create (or reuse) all Vodoo security groups."""
    warnings: list[str] = []
    group_ids: dict[str, int] = {}

    for group in GROUP_DEFINITIONS:
        group_id = await self._ensure_group(group)
        group_ids[group.name] = group_id

        for access in group.access:
            model_id = await self._get_model_id(access.model)
            if model_id is None:
                warnings.append(f"Model '{access.model}' not found; skipping access")
                continue
            await self._ensure_access(group_id, group.name, model_id, access)

        for rule in group.rules:
            model_id = await self._get_model_id(rule.model)
            if model_id is None:
                warnings.append(f"Model '{rule.model}' not found; skipping rule")
                continue
            await self._ensure_rule(group_id, group.name, model_id, rule)

    return group_ids, warnings

get_group_ids async

get_group_ids(group_names: list[str]) -> tuple[dict[str, int], list[str]]

Fetch group IDs for the provided names.

Source code in src/vodoo/aio/security.py
async def get_group_ids(
    self,
    group_names: list[str],
) -> tuple[dict[str, int], list[str]]:
    """Fetch group IDs for the provided names."""
    warnings: list[str] = []
    group_ids: dict[str, int] = {}

    for name in group_names:
        ids = await self._client.search("res.groups", domain=[("name", "=", name)], limit=1)
        if ids:
            group_ids[name] = ids[0]
        else:
            warnings.append(f"Group '{name}' not found")

    return group_ids, warnings

assign async

assign(user_id: int, group_ids: list[int], *, remove_default_groups: bool = True) -> None

Assign a user to the provided groups.

Source code in src/vodoo/aio/security.py
async def assign(
    self,
    user_id: int,
    group_ids: list[int],
    *,
    remove_default_groups: bool = True,
) -> None:
    """Assign a user to the provided groups."""
    commands: list[tuple[int, int]] = []

    if remove_default_groups:
        for xmlid in ("base.group_user", "base.group_portal"):
            gid = await self._get_group_id_by_xmlid(xmlid)
            if gid is not None:
                commands.append((3, gid))

    commands.extend((4, gid) for gid in group_ids)

    field = await self._groups_field()
    await self._client.write("res.users", [user_id], {field: commands})

resolve_user async

resolve_user(*, user_id: int | None = None, login: str | None = None) -> int

Resolve a user ID from either an ID or login name.

Source code in src/vodoo/aio/security.py
async def resolve_user(self, *, user_id: int | None = None, login: str | None = None) -> int:
    """Resolve a user ID from either an ID or login name."""
    if user_id is not None:
        return user_id
    if not login:
        raise ValueError("Provide --user-id or --login")

    ids = await self._client.search("res.users", domain=[("login", "=", login)], limit=1)
    if not ids:
        raise ValueError(f"User with login '{login}' not found")
    return ids[0]

create_user async

create_user(name: str, login: str, password: str | None = None, email: str | None = None) -> tuple[int, str]

Create a new user.

Source code in src/vodoo/aio/security.py
async def create_user(
    self,
    name: str,
    login: str,
    password: str | None = None,
    email: str | None = None,
) -> tuple[int, str]:
    """Create a new user."""
    if password is None:
        password = _generate_password()

    if email is None:
        email = login

    field = await self._groups_field()
    user_id = await self._client.create(
        "res.users",
        {
            "name": name,
            "login": login,
            "email": email,
            "password": password,
            field: [(6, 0, [])],
        },
    )

    return user_id, password

set_password async

set_password(user_id: int, password: str | None = None) -> str

Set a user's password.

Source code in src/vodoo/aio/security.py
async def set_password(
    self,
    user_id: int,
    password: str | None = None,
) -> str:
    """Set a user's password."""
    if password is None:
        password = _generate_password()

    await self._client.write("res.users", [user_id], {"password": password})
    return password

get_user async

get_user(user_id: int) -> dict[str, Any]

Get user information.

Source code in src/vodoo/aio/security.py
async def get_user(self, user_id: int) -> dict[str, Any]:
    """Get user information."""
    field = await self._groups_field()
    users = await self._client.search_read(
        "res.users",
        domain=[("id", "=", user_id)],
        fields=["name", "login", "email", "active", "share", field, "partner_id"],
        limit=1,
    )
    if not users:
        raise ValueError(f"User {user_id} not found")
    return users[0]