Skip to content

Groups API

The GroupsAPI client exposes the group read endpoints (list, members, edit form) and, since the admin write group opened by ADR 0001, the write endpoints: create, edit, delete and the members edit, for one group or in bulk.

Resource grouping

All endpoints are grouped under client.groups (D-v0.5-1), separate from PostsAPI or other resource clients.

Usage

from pynteracta.client import InteractaClient

with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
    # List groups (first page)
    page = client.groups.list_groups()
    for g in page.items_typed:
        print(g.id, g.name, g.members_count)

    # Iterate all pages lazily
    for g in client.groups.iterate_groups(full_text_filter="eng"):
        print(g.id, g.name)

    # List members of a group
    members = client.groups.list_members(201)
    for m in members.members_typed:
        print(m.id, m.full_name, m.email)

    # Iterate all member pages
    for m in client.groups.iterate_members(201, page_size=50):
        print(m.id, m.full_name)

    # Fetch group detail (for-edit form; includes members list and occToken)
    group = client.groups.get_for_edit(201)
    print(group.name, group.members_count)
    print(group.occ_token)  # the token to pass to edit() and edit_members()

Writing groups

create(), edit(), delete(), edit_members() and edit_members_bulk() follow the other write groups: explicit keyword arguments, *_raw() variants, a facade over the response. Only the fields you pass are sent, in one request.

from pynteracta.client import InteractaClient
from pynteracta.exceptions import ConcurrencyError

with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
    created = client.groups.create(name="QA", email="qa@tenant.example.com", visible=True)
    print(created.group_id, created.next_occ_token, created.members_count)

    # Edit: read first and send back every field that must survive (see "Omitted fields")
    group = client.groups.get_for_edit(created.group_id)
    edited = client.groups.edit(
        created.group_id,
        group.occ_token,
        name="QA team",
        email=group.email,
        visible=True,
    )
    print(edited.next_occ_token)

    # Members: add and remove by user id, with the token of the group
    group = client.groups.get_for_edit(created.group_id)
    try:
        result = client.groups.edit_members(
            created.group_id, group.occ_token, add_user_ids=[1042], remove_user_ids=[1099]
        )
    except ConcurrencyError:
        raise  # the group changed after we read it: re-read and decide, the library never retries
    print(result.next_occ_token)  # valid for the next members edit

    # Several groups in one request: the server reports successes and conflicts per group
    outcome = client.groups.edit_members_bulk(
        [{"id": 201, "occToken": 5, "addUserIds": [1042]}, {"id": 202, "occToken": 1}]
    )
    print([g.id for g in outcome.success_groups], [g.id for g in outcome.concurrency_error_groups])

    client.groups.delete(created.group_id)

GroupWriteResult and GroupMembersResult

create(), edit() and edit_members() return a GroupWriteResult: group_id, next_occ_token, name, email, visible, members_count and .raw. delete() returns nothing. edit_members_bulk() returns a GroupMembersResult with success_groups and concurrency_error_groups, lists of GroupSummary (id, name, members_count, occ_token), and does not raise for conflicts: that decision belongs to the caller.

Concurrency: occ_token

edit() and edit_members() take the token read with get_for_edit() (GroupForEdit.occ_token). edit() gets a 409 → ConcurrencyError when the group changed. The members endpoint answers 200 even on conflict, listing the group under concurrencyErrorGroups: edit_members() raises ConcurrencyError with status_code == 200 and the response body attached. The token returned by a members edit is valid for the next one (verified on a tenant). The library never re-reads and retries (ADR 0001).

Omitted fields in edit(): the server replaces the group

Verified against a tenant (spec 05): edit() requires name (400 REQUIRED_FIELD) and clears email, external_id and visible when they are missing from the request (visible becomes False, i.e. a system group). The members are the exception: member_ids you omit are kept; when you pass it, it is the complete list. Use edit_members() to add or remove single users.

Pass every field you want to keep

Read the group first and send back name, email, external id and visibility. The CLI groups edit does this for you and never touches the members.

Deleting a group

After delete() the group is gone: get_for_edit() answers 404 (NotFoundError).

Sort fields for list_groups

The API uses orderTypeId (not orderBy). Valid values: 'name', 'email'. Pass as order_type_id kwarg; order_desc controls direction.

API Reference

pynteracta.api.groups.GroupsAPI

Bases: ResourceClient

Client for group listing, member listing, group-for-edit and admin write endpoints.

Le scritture (spec 05) inviano solo i campi passati, in una sola richiesta: un errore del server o di rete risale al chiamante, mai un nuovo tentativo (ADR 0001). Il token di concorrenza lo fornisce il chiamante, letto da GroupForEdit.occ_token; un 409 è ConcurrencyError.

list_groups(*, page_token=None, page_size=None, full_text_filter=None, status_filter=None, workspace_ids=None, order_type_id=None, order_desc=None)

POST /admin/data/groups.

Parameters:

Name Type Description Default
page_token str | None

Pagination cursor from a previous response.

None
page_size int | None

Maximum items per page.

None
full_text_filter str | None

Full-text filter on group name and email.

None
status_filter list[int] | None

Filter by group status codes.

None
workspace_ids list[int] | None

Filter by workspace IDs.

None
order_type_id str | None

Sort field. Valid values: 'name', 'email'.

None
order_desc bool | None

True for descending, False for ascending (default: True).

None

list_groups_raw(req)

POST group list with a pre-built request DTO (escape hatch).

iterate_groups(*, page_size=None, full_text_filter=None, status_filter=None, workspace_ids=None, order_type_id=None, order_desc=None)

Lazy iterator over all pages of :meth:list_groups.

list_members(group_id, *, page_token=None, page_size=None)

POST /admin/data/groups/{groupId}/members.

Parameters:

Name Type Description Default
group_id int

The group whose members to list.

required
page_token str | None

Pagination cursor.

None
page_size int | None

Maximum items per page.

None

iterate_members(group_id, *, page_size=None)

Lazy iterator over all pages of :meth:list_members.

get_for_edit(group_id)

GET /admin/manage/groups/{groupId}/edit.

Parameters:

Name Type Description Default
group_id int

The group ID to fetch.

required

create(*, name=None, email=None, external_id=None, visible=None, member_ids=None)

POST /admin/manage/groups: crea un gruppo.

Parameters:

Name Type Description Default
name str | None

Nome del gruppo.

None
email str | None

Email del gruppo.

None
external_id str | None

Riferimento esterno.

None
visible bool | None

True = visibile per le menzioni; False = gruppo di sistema.

None
member_ids list[int] | None

Id degli utenti membri.

None

create_raw(req)

POST /admin/manage/groups da un DTO già costruito.

edit(group_id, occ_token, *, name=None, email=None, external_id=None, visible=None, member_ids=None)

PUT /admin/manage/groups/{groupId}: modifica un gruppo.

Il corpo contiene solo i campi passati più l'occToken. member_ids, se passato, è la lista completa dei membri; per aggiungere o togliere singoli utenti si usa :meth:edit_members. I campi omessi non vengono inviati: cosa ne fa il server è scritto in docs/api/groups.md.

Parameters:

Name Type Description Default
group_id int

Il gruppo da modificare.

required
occ_token int

Token di concorrenza letto da GroupForEdit.occ_token.

required
name str | None

Nome del gruppo.

None
email str | None

Email del gruppo.

None
external_id str | None

Riferimento esterno.

None
visible bool | None

Visibilità per le menzioni.

None
member_ids list[int] | None

Lista completa degli id dei membri.

None

edit_raw(group_id, req)

PUT /admin/manage/groups/{groupId} da un DTO già costruito, occToken compreso.

delete(group_id)

DELETE /admin/manage/groups/{groupId}: elimina un gruppo; la risposta è vuota.

edit_members(group_id, occ_token, *, add_user_ids=None, remove_user_ids=None)

PUT /admin/manage/groups/members per un solo gruppo.

Il server risponde 200 con due liste: se il gruppo è in successGroups il risultato porta il suo nuovo next_occ_token; se è in concurrencyErrorGroups la chiamata solleva ConcurrencyError (stato 200, corpo allegato); se non è in nessuna delle due solleva InteractaError. Una sola richiesta in ogni caso.

Parameters:

Name Type Description Default
group_id int

Il gruppo.

required
occ_token int

Token di concorrenza letto da GroupForEdit.occ_token.

required
add_user_ids list[int] | None

Id degli utenti da aggiungere.

None
remove_user_ids list[int] | None

Id degli utenti da togliere.

None

edit_members_bulk(groups)

PUT /admin/manage/groups/members per più gruppi in una sola richiesta.

Ogni elemento è {"id", "occToken", "addUserIds", "deleteUserIds"} (dict o DTO). Il risultato riporta success_groups e concurrency_error_groups; non solleva per i conflitti: decide il chiamante.

edit_members_bulk_raw(req)

PUT /admin/manage/groups/members da un DTO già costruito.

Facade Reference

pynteracta.models.facade.groups.Group

Narrow facade over :class:~generated.ListSystemGroupsElementDTOModel.

ListSystemGroupsResponseDTO.items are typed as ListSystemGroupsElementDTO (RootModel[Any] stubs); bind to the typed ListSystemGroupsElementDTOModel.

Attributes:

Name Type Description
raw

The underlying typed DTO; access additional fields via this escape hatch.

Source code in src/pynteracta/models/facade/groups.py
class Group:
    """Narrow facade over :class:`~generated.ListSystemGroupsElementDTOModel`.

    ``ListSystemGroupsResponseDTO.items`` are typed as ``ListSystemGroupsElementDTO``
    (``RootModel[Any]`` stubs); bind to the typed ``ListSystemGroupsElementDTOModel``.

    Attributes:
        raw: The underlying typed DTO; access additional fields via this escape hatch.
    """

    def __init__(self, raw: generated.ListSystemGroupsElementDTOModel) -> None:
        self.raw = raw

    @property
    def id(self) -> int | None:
        return self.raw.id

    @property
    def name(self) -> str | None:
        return self.raw.name

    @property
    def email(self) -> str | None:
        return self.raw.email

    @property
    def description(self) -> str | None:
        return self.raw.description

    @property
    def members_count(self) -> int | None:
        return self.raw.membersCount

    @property
    def visible(self) -> bool | None:
        return self.raw.visible

    @property
    def deleted(self) -> bool | None:
        return self.raw.deleted

    @property
    def creation_timestamp(self) -> int | None:
        return self.raw.creationTimestamp

    @property
    def tags_typed(self) -> list[Tag]:
        """Re-validate each opaque ``TagDTO`` stub into :class:`Tag`."""
        if not self.raw.tags:
            return []
        result = []
        for t in self.raw.tags:
            root = _resolve_root(t)
            if isinstance(root, dict):
                result.append(Tag(generated.TagDTO1.model_validate(root)))
        return result

    @classmethod
    def from_dict(cls, data: dict) -> Group:  # type: ignore[type-arg]
        """Parse from a raw dict item."""
        raw = generated.ListSystemGroupsElementDTOModel.model_validate(data)
        return cls(raw)

tags_typed property

Re-validate each opaque TagDTO stub into :class:Tag.

from_dict(data) classmethod

Parse from a raw dict item.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_dict(cls, data: dict) -> Group:  # type: ignore[type-arg]
    """Parse from a raw dict item."""
    raw = generated.ListSystemGroupsElementDTOModel.model_validate(data)
    return cls(raw)

pynteracta.models.facade.groups.GroupList

Narrow facade over :class:~generated.ListSystemGroupsResponseDTO.

items are ListSystemGroupsElementDTO (RootModel[Any] stubs); call :meth:items_typed to get :class:Group instances.

Attributes:

Name Type Description
raw

The underlying generated DTO; access additional fields via this escape hatch.

Source code in src/pynteracta/models/facade/groups.py
class GroupList:
    """Narrow facade over :class:`~generated.ListSystemGroupsResponseDTO`.

    ``items`` are ``ListSystemGroupsElementDTO`` (``RootModel[Any]`` stubs); call
    :meth:`items_typed` to get :class:`Group` instances.

    Attributes:
        raw: The underlying generated DTO; access additional fields via this escape hatch.
    """

    def __init__(self, raw: generated.ListSystemGroupsResponseDTO) -> None:
        self.raw = raw

    @property
    def next_page_token(self) -> str | None:
        return self.raw.nextPageToken

    @property
    def total_items_count(self) -> int | None:
        return self.raw.totalItemsCount

    @property
    def items_typed(self) -> list[Group]:
        """Re-validate each opaque list item into :class:`Group`."""
        if not self.raw.items:
            return []
        result = []
        for item in self.raw.items:
            root = _resolve_root(item)
            if isinstance(root, dict):
                result.append(Group(generated.ListSystemGroupsElementDTOModel.model_validate(root)))
        return result

    @classmethod
    def from_dict(cls, data: dict) -> GroupList:  # type: ignore[type-arg]
        """Parse from a raw API response dict."""
        raw = generated.ListSystemGroupsResponseDTO.model_validate(data)
        return cls(raw)

items_typed property

Re-validate each opaque list item into :class:Group.

from_dict(data) classmethod

Parse from a raw API response dict.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_dict(cls, data: dict) -> GroupList:  # type: ignore[type-arg]
    """Parse from a raw API response dict."""
    raw = generated.ListSystemGroupsResponseDTO.model_validate(data)
    return cls(raw)

pynteracta.models.facade.groups.GroupMember

Thin facade over :class:~generated.UserDTOModel for a group member.

ListGroupMembersResponseDTO.items and GetGroupForEditResponseDTO.members are typed as list[UserDTO] (RootModel[Any] stubs); this facade wraps the re-validated typed sibling.

Attributes:

Name Type Description
raw

The underlying typed DTO.

Source code in src/pynteracta/models/facade/groups.py
class GroupMember:
    """Thin facade over :class:`~generated.UserDTOModel` for a group member.

    ``ListGroupMembersResponseDTO.items`` and ``GetGroupForEditResponseDTO.members`` are typed as
    ``list[UserDTO]`` (``RootModel[Any]`` stubs); this facade wraps the re-validated typed sibling.

    Attributes:
        raw: The underlying typed DTO.
    """

    def __init__(self, raw: generated.UserDTOModel) -> None:
        self.raw = raw

    @property
    def id(self) -> int | None:
        return self.raw.id

    @property
    def first_name(self) -> str | None:
        return self.raw.firstName

    @property
    def last_name(self) -> str | None:
        return self.raw.lastName

    @property
    def full_name(self) -> str | None:
        parts = [p for p in (self.raw.firstName, self.raw.lastName) if p]
        return " ".join(parts) if parts else None

    @property
    def email(self) -> str | None:
        return self.raw.contactEmail

    @property
    def deleted(self) -> bool | None:
        return self.raw.deleted

    @property
    def blocked(self) -> bool | None:
        return self.raw.blocked

    @classmethod
    def from_stub(cls, stub: generated.UserDTO) -> GroupMember:
        """Re-validate a ``UserDTO`` ``RootModel[Any]`` stub into :class:`GroupMember`."""
        root = _resolve_root(stub)
        if isinstance(root, dict):
            return cls(generated.UserDTOModel.model_validate(root))
        msg = f"Unexpected stub root type: {type(root)}"
        raise ValueError(msg)

from_stub(stub) classmethod

Re-validate a UserDTO RootModel[Any] stub into :class:GroupMember.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_stub(cls, stub: generated.UserDTO) -> GroupMember:
    """Re-validate a ``UserDTO`` ``RootModel[Any]`` stub into :class:`GroupMember`."""
    root = _resolve_root(stub)
    if isinstance(root, dict):
        return cls(generated.UserDTOModel.model_validate(root))
    msg = f"Unexpected stub root type: {type(root)}"
    raise ValueError(msg)

pynteracta.models.facade.groups.GroupMemberList

Narrow facade over :class:~generated.ListGroupMembersResponseDTO.

Attributes:

Name Type Description
raw

The underlying generated DTO; access additional fields via this escape hatch.

Source code in src/pynteracta/models/facade/groups.py
class GroupMemberList:
    """Narrow facade over :class:`~generated.ListGroupMembersResponseDTO`.

    Attributes:
        raw: The underlying generated DTO; access additional fields via this escape hatch.
    """

    def __init__(self, raw: generated.ListGroupMembersResponseDTO) -> None:
        self.raw = raw

    @property
    def next_page_token(self) -> str | None:
        return self.raw.nextPageToken

    @property
    def total_items_count(self) -> int | None:
        return self.raw.totalItemsCount

    @property
    def members_typed(self) -> list[GroupMember]:
        """Re-validate each opaque ``UserDTO`` stub into :class:`GroupMember`."""
        if not self.raw.items:
            return []
        result = []
        for item in self.raw.items:
            root = _resolve_root(item)
            if isinstance(root, dict):
                result.append(GroupMember(generated.UserDTOModel.model_validate(root)))
        return result

    @classmethod
    def from_dict(cls, data: dict) -> GroupMemberList:  # type: ignore[type-arg]
        """Parse from a raw API response dict."""
        raw = generated.ListGroupMembersResponseDTO.model_validate(data)
        return cls(raw)

members_typed property

Re-validate each opaque UserDTO stub into :class:GroupMember.

from_dict(data) classmethod

Parse from a raw API response dict.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_dict(cls, data: dict) -> GroupMemberList:  # type: ignore[type-arg]
    """Parse from a raw API response dict."""
    raw = generated.ListGroupMembersResponseDTO.model_validate(data)
    return cls(raw)

pynteracta.models.facade.groups.GroupForEdit

Narrow facade over :class:~generated.GetGroupForEditResponseDTO.

The members list contains UserDTO (RootModel[Any] stubs); call :meth:members_typed to re-validate them. :attr:occ_token è il token di concorrenza da passare a edit ed edit_members (spec 05).

Attributes:

Name Type Description
raw

The underlying generated DTO; access additional fields via this escape hatch.

Source code in src/pynteracta/models/facade/groups.py
class GroupForEdit:
    """Narrow facade over :class:`~generated.GetGroupForEditResponseDTO`.

    The ``members`` list contains ``UserDTO`` (``RootModel[Any]`` stubs); call
    :meth:`members_typed` to re-validate them. :attr:`occ_token` è il token di concorrenza da
    passare a ``edit`` ed ``edit_members`` (spec 05).

    Attributes:
        raw: The underlying generated DTO; access additional fields via this escape hatch.
    """

    def __init__(self, raw: generated.GetGroupForEditResponseDTO) -> None:
        self.raw = raw

    @property
    def id(self) -> int | None:
        return self.raw.id

    @property
    def name(self) -> str | None:
        return self.raw.name

    @property
    def email(self) -> str | None:
        return self.raw.email

    @property
    def description(self) -> str | None:
        return self.raw.description

    @property
    def members_count(self) -> int | None:
        return self.raw.membersCount

    @property
    def visible(self) -> bool | None:
        return self.raw.visible

    @property
    def deleted(self) -> bool | None:
        return self.raw.deleted

    @property
    def creation_timestamp(self) -> int | None:
        return self.raw.creationTimestamp

    @property
    def occ_token(self) -> int | None:
        """Token di concorrenza da passare a ``edit`` ed ``edit_members`` (spec 05, RF-023a)."""
        return self.raw.occToken

    @property
    def tags_typed(self) -> list[Tag]:
        """Re-validate each opaque ``TagDTO`` stub into :class:`Tag`."""
        if not self.raw.tags:
            return []
        result = []
        for t in self.raw.tags:
            root = _resolve_root(t)
            if isinstance(root, dict):
                result.append(Tag(generated.TagDTO1.model_validate(root)))
        return result

    @property
    def members_typed(self) -> list[GroupMember]:
        """Re-validate each opaque ``UserDTO`` stub into :class:`GroupMember`."""
        if not self.raw.members:
            return []
        result = []
        for item in self.raw.members:
            root = _resolve_root(item)
            if isinstance(root, dict):
                result.append(GroupMember(generated.UserDTOModel.model_validate(root)))
        return result

    @classmethod
    def from_dict(cls, data: dict) -> GroupForEdit:  # type: ignore[type-arg]
        """Parse from a raw API response dict."""
        raw = generated.GetGroupForEditResponseDTO.model_validate(data)
        return cls(raw)

members_typed property

Re-validate each opaque UserDTO stub into :class:GroupMember.

occ_token property

Token di concorrenza da passare a edit ed edit_members (spec 05, RF-023a).

tags_typed property

Re-validate each opaque TagDTO stub into :class:Tag.

from_dict(data) classmethod

Parse from a raw API response dict.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_dict(cls, data: dict) -> GroupForEdit:  # type: ignore[type-arg]
    """Parse from a raw API response dict."""
    raw = generated.GetGroupForEditResponseDTO.model_validate(data)
    return cls(raw)

pynteracta.models.facade.groups.GroupSummary

Façade sul GroupDTO restituito nelle liste di edit_members (spec 05).

successGroups e concurrencyErrorGroups sono liste di stub RootModel[Any]; la façade avvolge il gemello tipizzato GroupDTOModel.

Attributes:

Name Type Description
raw

Il DTO tipizzato sottostante.

Source code in src/pynteracta/models/facade/groups.py
class GroupSummary:
    """Façade sul ``GroupDTO`` restituito nelle liste di ``edit_members`` (spec 05).

    ``successGroups`` e ``concurrencyErrorGroups`` sono liste di stub ``RootModel[Any]``; la
    façade avvolge il gemello tipizzato ``GroupDTOModel``.

    Attributes:
        raw: Il DTO tipizzato sottostante.
    """

    def __init__(self, raw: generated.GroupDTOModel) -> None:
        self.raw = raw

    @property
    def id(self) -> int | None:
        return self.raw.id

    @property
    def name(self) -> str | None:
        return self.raw.name

    @property
    def email(self) -> str | None:
        return self.raw.email

    @property
    def visible(self) -> bool | None:
        return self.raw.visible

    @property
    def deleted(self) -> bool | None:
        return self.raw.deleted

    @property
    def members_count(self) -> int | None:
        return self.raw.membersCount

    @property
    def occ_token(self) -> int | None:
        """Token di concorrenza del gruppo dopo la scrittura."""
        return self.raw.occToken

    @classmethod
    def from_stub(cls, stub: generated.GroupDTO) -> GroupSummary:
        """Rivalida uno stub ``GroupDTO`` in :class:`GroupSummary`."""
        root = _resolve_root(stub)
        if isinstance(root, dict):
            return cls(generated.GroupDTOModel.model_validate(root))
        msg = f"Unexpected stub root type: {type(root)}"
        raise ValueError(msg)

occ_token property

Token di concorrenza del gruppo dopo la scrittura.

from_stub(stub) classmethod

Rivalida uno stub GroupDTO in :class:GroupSummary.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_stub(cls, stub: generated.GroupDTO) -> GroupSummary:
    """Rivalida uno stub ``GroupDTO`` in :class:`GroupSummary`."""
    root = _resolve_root(stub)
    if isinstance(root, dict):
        return cls(generated.GroupDTOModel.model_validate(root))
    msg = f"Unexpected stub root type: {type(root)}"
    raise ValueError(msg)

pynteracta.models.facade.groups.GroupWriteResult

Façade sulla risposta di create, edit ed edit_members di un gruppo (spec 05).

I DTO non hanno gli stessi campi: le proprietà assenti valgono None. group_id viene da groupId (creazione) o id (membri), altrimenti è quello passato dal chiamante; next_occ_token viene da nextOccToken o, per il gruppo restituito da edit_members, dal suo occToken.

Attributes:

Name Type Description
raw

Il DTO generato sottostante (CreateGroupResponseDTO, EditGroupResponseDTO o GroupDTOModel).

Source code in src/pynteracta/models/facade/groups.py
class GroupWriteResult:
    """Façade sulla risposta di ``create``, ``edit`` ed ``edit_members`` di un gruppo (spec 05).

    I DTO non hanno gli stessi campi: le proprietà assenti valgono ``None``. ``group_id`` viene
    da ``groupId`` (creazione) o ``id`` (membri), altrimenti è quello passato dal chiamante;
    ``next_occ_token`` viene da ``nextOccToken`` o, per il gruppo restituito da ``edit_members``,
    dal suo ``occToken``.

    Attributes:
        raw: Il DTO generato sottostante (``CreateGroupResponseDTO``, ``EditGroupResponseDTO`` o
            ``GroupDTOModel``).
    """

    def __init__(
        self,
        raw: (
            generated.CreateGroupResponseDTO
            | generated.EditGroupResponseDTO
            | generated.GroupDTOModel
        ),
        *,
        group_id: int | None = None,
    ) -> None:
        self.raw = raw
        self._group_id = group_id

    @property
    def group_id(self) -> int | None:
        """Id del gruppo scritto: dalla risposta, altrimenti quello passato."""
        for attr in ("groupId", "id"):
            value = getattr(self.raw, attr, None)
            if value is not None:
                return int(value)
        return self._group_id

    @property
    def next_occ_token(self) -> int | None:
        """Token di concorrenza da usare per la modifica successiva."""
        value: int | None = getattr(self.raw, "nextOccToken", None)
        if value is not None:
            return value
        occ: int | None = getattr(self.raw, "occToken", None)
        return occ

    @property
    def name(self) -> str | None:
        value: str | None = getattr(self.raw, "name", None)
        return value

    @property
    def email(self) -> str | None:
        value: str | None = getattr(self.raw, "email", None)
        return value

    @property
    def visible(self) -> bool | None:
        value: bool | None = getattr(self.raw, "visible", None)
        return value

    @property
    def members_count(self) -> int | None:
        value: int | None = getattr(self.raw, "membersCount", None)
        return value

    @classmethod
    def from_create(cls, data: dict[str, Any]) -> GroupWriteResult:
        """Legge la risposta di ``POST admin/manage/groups``."""
        return cls(generated.CreateGroupResponseDTO.model_validate(data))

    @classmethod
    def from_edit(cls, data: dict[str, Any], group_id: int) -> GroupWriteResult:
        """Legge la risposta di ``PUT admin/manage/groups/{groupId}``."""
        return cls(generated.EditGroupResponseDTO.model_validate(data), group_id=group_id)

    @classmethod
    def from_member_edit(cls, summary: GroupSummary) -> GroupWriteResult:
        """Avvolge il gruppo restituito in ``successGroups`` da ``edit_members``."""
        return cls(summary.raw, group_id=summary.id)

group_id property

Id del gruppo scritto: dalla risposta, altrimenti quello passato.

next_occ_token property

Token di concorrenza da usare per la modifica successiva.

from_create(data) classmethod

Legge la risposta di POST admin/manage/groups.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_create(cls, data: dict[str, Any]) -> GroupWriteResult:
    """Legge la risposta di ``POST admin/manage/groups``."""
    return cls(generated.CreateGroupResponseDTO.model_validate(data))

from_edit(data, group_id) classmethod

Legge la risposta di PUT admin/manage/groups/{groupId}.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_edit(cls, data: dict[str, Any], group_id: int) -> GroupWriteResult:
    """Legge la risposta di ``PUT admin/manage/groups/{groupId}``."""
    return cls(generated.EditGroupResponseDTO.model_validate(data), group_id=group_id)

from_member_edit(summary) classmethod

Avvolge il gruppo restituito in successGroups da edit_members.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_member_edit(cls, summary: GroupSummary) -> GroupWriteResult:
    """Avvolge il gruppo restituito in ``successGroups`` da ``edit_members``."""
    return cls(summary.raw, group_id=summary.id)

pynteracta.models.facade.groups.GroupMembersResult

Façade sulla risposta di PUT admin/manage/groups/members (spec 05).

Il server risponde 200 anche con conflitti: :attr:success_groups e :attr:concurrency_error_groups dicono com'è andata gruppo per gruppo.

Attributes:

Name Type Description
raw

Il DTO generato sottostante.

Source code in src/pynteracta/models/facade/groups.py
class GroupMembersResult:
    """Façade sulla risposta di ``PUT admin/manage/groups/members`` (spec 05).

    Il server risponde ``200`` anche con conflitti: :attr:`success_groups` e
    :attr:`concurrency_error_groups` dicono com'è andata gruppo per gruppo.

    Attributes:
        raw: Il DTO generato sottostante.
    """

    def __init__(self, raw: generated.EditMultipleGroupsMembersResponseDTO) -> None:
        self.raw = raw

    @staticmethod
    def _summaries(items: list[generated.GroupDTO] | None) -> list[GroupSummary]:
        return [GroupSummary.from_stub(item) for item in items or []]

    @property
    def success_groups(self) -> list[GroupSummary]:
        """Gruppi modificati, con il nuovo ``occ_token``."""
        return self._summaries(self.raw.successGroups)

    @property
    def concurrency_error_groups(self) -> list[GroupSummary]:
        """Gruppi non modificati perché cambiati dopo la lettura dell'``occToken``."""
        return self._summaries(self.raw.concurrencyErrorGroups)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> GroupMembersResult:
        """Parse from a raw API response dict."""
        return cls(generated.EditMultipleGroupsMembersResponseDTO.model_validate(data))

concurrency_error_groups property

Gruppi non modificati perché cambiati dopo la lettura dell'occToken.

success_groups property

Gruppi modificati, con il nuovo occ_token.

from_dict(data) classmethod

Parse from a raw API response dict.

Source code in src/pynteracta/models/facade/groups.py
@classmethod
def from_dict(cls, data: dict[str, Any]) -> GroupMembersResult:
    """Parse from a raw API response dict."""
    return cls(generated.EditMultipleGroupsMembersResponseDTO.model_validate(data))

pynteracta.models.facade.groups.Tag

Thin facade over :class:~generated.TagDTO1.

Attributes:

Name Type Description
raw

The underlying typed DTO.

Source code in src/pynteracta/models/facade/groups.py
class Tag:
    """Thin facade over :class:`~generated.TagDTO1`.

    Attributes:
        raw: The underlying typed DTO.
    """

    def __init__(self, raw: generated.TagDTO1) -> None:
        self.raw = raw

    @property
    def id(self) -> int | None:
        return self.raw.id

    @property
    def name(self) -> str | None:
        return self.raw.name

    @property
    def visible(self) -> bool | None:
        return self.raw.visible