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: |
None
|
order_desc
|
bool | None
|
|
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
|
|
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 |
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 |
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
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
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
from_stub(stub)
classmethod
¶
Re-validate a UserDTO RootModel[Any] stub into :class:GroupMember.
Source code in src/pynteracta/models/facade/groups.py
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
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
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | |
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.
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
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
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 ( |
Source code in src/pynteracta/models/facade/groups.py
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | |
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.
from_edit(data, group_id)
classmethod
¶
Legge la risposta di PUT admin/manage/groups/{groupId}.
Source code in src/pynteracta/models/facade/groups.py
from_member_edit(summary)
classmethod
¶
Avvolge il gruppo restituito in successGroups da edit_members.
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
pynteracta.models.facade.groups.Tag
¶
Thin facade over :class:~generated.TagDTO1.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying typed DTO. |