Users API¶
The UsersAPI client exposes the user read endpoints (system user list, own profile, edit form)
and, since the admin write group opened by ADR 0001, the four admin write endpoints: create, edit,
delete and edit credentials.
Usage¶
from pynteracta.client import InteractaClient
with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
page = client.users.list(page_size=50)
for u in page.items_typed:
print(u.id, u.firstName, u.lastName, u.contactEmail)
me = client.users.profile()
print(me.first_name, me.contact_email)
# Edit form (admin): the current state plus the optimistic-concurrency token
user = client.users.get_for_edit(1042)
print(user.first_name, user.last_name, user.contact_email, user.blocked)
print(user.occ_token) # the token to pass to edit()
UserForEdit.blocked is read-only: the edit DTO has no blocked field, so blocking and
unblocking a user is not something this library can do.
Writing users¶
create(), edit(), delete() and edit_credentials() mirror the other write groups: explicit
snake_case keyword arguments, a *_raw() variant for callers holding a pre-built DTO, and a
facade over the server response. Only the fields you pass are sent, in one request; nested
blocks (user_preferences, user_info, user_settings, user_credentials_configuration,
reset_user_custom_credentials_command) are passed as dicts in the shape of the DTO (camelCase
keys) or as generated DTOs.
from pynteracta.client import InteractaClient
from pynteracta.exceptions import ConcurrencyError
with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
created = client.users.create(
firstname="Maria",
lastname="Rossi",
contact_email="m.rossi@tenant.example.com",
user_credentials_configuration={
"custom": {"username": "m.rossi@tenant.example.com", "active": True}
},
reset_user_custom_credentials_command={"generatePassword": True},
)
print(created.user_id, created.next_occ_token)
print(created.generated_password) # ["..."]: hand it over, it is shown only here
# Edit: read first, pass the token, and send back every field that must survive
user = client.users.get_for_edit(created.user_id)
try:
edited = client.users.edit(
created.user_id,
user.occ_token,
firstname=user.first_name,
lastname="Rossi-Bianchi",
contact_email=user.contact_email,
)
except ConcurrencyError:
raise # the user changed after we read it: re-read and decide, the library never retries
print(edited.next_occ_token)
# Credentials: only the blocks you pass are touched
creds = client.users.get_credentials_for_edit(created.user_id)
client.users.edit_credentials(
created.user_id,
creds.occ_token,
google={"googleAccountId": "m.rossi@tenant.example.com", "enabled": True},
)
client.users.delete(created.user_id)
UserWriteResult¶
create(), edit() and edit_credentials() return a UserWriteResult: user_id (from the
create response, otherwise the id you passed), next_occ_token (the token for the next edit),
generated_password, expired_credentials, sent_email_notify (create only),
account_photo_url, and .raw (the generated response DTO). delete() returns nothing: the
response has no body.
Concurrency: occ_token¶
edit() and edit_credentials() take the token read with get_for_edit() (UserForEdit.occ_token)
and get_credentials_for_edit() (UserCredentialsForEdit.occ_token). If the user changed in the
meantime the server answers 409, mapped to ConcurrencyError. The library does not re-read
and retry (ADR 0001): one request per call, also on timeouts and network errors, whose outcome
stays unknown until you check.
Generated password¶
Ask the server to generate the custom password with
reset_user_custom_credentials_command={"generatePassword": True}, or set one with
{"password": ["..."]}; forceCredentialsExpiration forces a change at first login and
emailNotifyRecipients sends it by email. The password can only be set at creation: the
credentials edit DTO has no password field. The swagger declares generatedPassword as a list of
strings while the tenant returns a single string: generated_password always gives you a list.
Request and response bodies are redacted before they reach logs, audit log and hooks
(password, generatedPassword → ***REDACTED***), and a malformed create response raises a
ValueError that names the fields, never the values.
Omitted fields in edit(): the server replaces the user¶
Verified against a tenant (spec 05): edit() requires firstname and lastname (400
REQUIRED_FIELD otherwise) and treats the request as a replacement of the scalar fields:
contact_email, private_email and external_id that are missing from the request are
cleared. The nested blocks are different: user_preferences, user_info and user_settings
you omit are kept.
Pass every scalar field you want to keep
Read the user first and send back first name, last name, contact email, private email and
external id. The CLI users edit does this for you.
Credential blocks in edit_credentials(): omitted blocks are kept¶
edit_credentials() takes up to three blocks, google, microsoft and custom. A block you do
not pass is kept as it is (a call without any block changes nothing). The server has no notion
of a disabled block: to remove one, send it with the flag false and no account id
(custom={"active": False}, google={"enabled": False}); an account id or username together
with the flag false is rejected (400 INVALID_VALUE). custom.active is required whenever the
custom block is present (400 REQUIRED_FIELD), and usernames and account ids must belong to
the tenant's domain (400 INVALID_DOMAIN).
Deleting a user¶
After delete() the user is gone: the credentials form answers 404 (NotFoundError) and the
edit form answers 204 with an empty body, which get_for_edit() maps to NotFoundError as well
(status_code == 204). The tenant gives that 204 for any unknown user id.
API Reference¶
pynteracta.api.users.UsersAPI
¶
Bases: ResourceClient
Client for user listing, profile, admin lookup 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 UserForEdit.occ_token o
UserCredentialsForEdit.occ_token; un 409 è ConcurrencyError. La semantica del
server sui campi omessi in edit ed edit_credentials è documentata in
docs/api/users.md.
create(*, firstname=None, lastname=None, contact_email=None, private_email=None, external_id=None, user_preferences=None, user_info=None, user_settings=None, user_credentials_configuration=None, reset_user_custom_credentials_command=None)
¶
POST /admin/manage/users: crea un utente.
Il corpo contiene solo i campi passati, in camelCase. I blocchi annidati sono dict nella
forma del DTO o DTO generati. La password custom si imposta o si fa generare solo qui,
con reset_user_custom_credentials_command (generatePassword oppure password).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
firstname
|
str | None
|
Nome. |
None
|
lastname
|
str | None
|
Cognome. |
None
|
contact_email
|
str | None
|
Email di contatto. |
None
|
private_email
|
str | None
|
Email privata. |
None
|
external_id
|
str | None
|
Riferimento esterno. |
None
|
user_preferences
|
WriteBlock
|
|
None
|
user_info
|
WriteBlock
|
|
None
|
user_settings
|
WriteBlock
|
|
None
|
user_credentials_configuration
|
WriteBlock
|
|
None
|
reset_user_custom_credentials_command
|
WriteBlock
|
|
None
|
create_raw(req)
¶
POST /admin/manage/users da un DTO già costruito.
delete(user_id)
¶
DELETE /admin/manage/users/{userId}: elimina un utente. La risposta non ha corpo.
edit(user_id, occ_token, *, firstname=None, lastname=None, contact_email=None, private_email=None, external_id=None, user_preferences=None, user_info=None, user_settings=None)
¶
PUT /admin/manage/users/{userId}: modifica un utente.
Il corpo contiene solo i campi passati più l'occToken. I campi omessi non vengono
inviati: cosa ne fa il server è scritto in docs/api/users.md.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
L'utente da modificare. |
required |
occ_token
|
int
|
Token di concorrenza letto da |
required |
firstname
|
str | None
|
Nome. |
None
|
lastname
|
str | None
|
Cognome. |
None
|
contact_email
|
str | None
|
Email di contatto. |
None
|
private_email
|
str | None
|
Email privata. |
None
|
external_id
|
str | None
|
Riferimento esterno. |
None
|
user_preferences
|
WriteBlock
|
|
None
|
user_info
|
WriteBlock
|
|
None
|
user_settings
|
WriteBlock
|
|
None
|
edit_credentials(user_id, occ_token, *, google=None, microsoft=None, custom=None)
¶
PUT /admin/manage/users/{userId}/credentials: modifica le credenziali.
userCredentialsConfiguration contiene solo i blocchi passati. La password custom non
si cambia da qui: il DTO non la prevede (solo alla creazione).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
int
|
L'utente. |
required |
occ_token
|
int
|
Token letto da |
required |
google
|
WriteBlock
|
|
None
|
microsoft
|
WriteBlock
|
|
None
|
custom
|
WriteBlock
|
|
None
|
edit_credentials_raw(user_id, req)
¶
PUT /admin/manage/users/{userId}/credentials da un DTO già costruito.
edit_raw(user_id, req)
¶
PUT /admin/manage/users/{userId} da un DTO già costruito (occToken compreso).
get_credentials_for_edit(user_id)
¶
GET /admin/manage/users/{userId}/credentials/edit.
Alias di :meth:~pynteracta.api.admin_manage.AdminManageAPI.user_credentials_for_edit:
stessa richiesta, stessa façade, con occ_token per :meth:edit_credentials.
get_for_edit(user_id)
¶
GET /admin/manage/users/{userId}/edit — requires admin permissions.
iterate(*, page_size=None, **filters)
¶
Lazy iterator over all pages of :meth:list.
list(*, page_token=None, page_size=None, calculate_total_items_count=None, full_text_filter=None, status_filter=None, workspace_ids=None, community_ids=None, creation_timestamp_from=None, creation_timestamp_to=None, last_access_timestamp_from=None, last_access_timestamp_to=None, role=None, order_by=None, order_desc=None, **filters)
¶
POST /admin/data/users with curated filter and ordering kwargs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
page_token
|
str | None
|
Opaque token for the page to fetch. |
None
|
page_size
|
int | None
|
Items per page. |
None
|
calculate_total_items_count
|
bool | None
|
Ask the API to populate |
None
|
full_text_filter
|
str | None
|
Full-text filter on name, surname, and email
( |
None
|
status_filter
|
list[int] | None
|
Filter by user status ids ( |
None
|
workspace_ids
|
list[int] | None
|
Filter by workspace ids ( |
None
|
community_ids
|
list[int] | None
|
Filter by community ids ( |
None
|
creation_timestamp_from
|
int | float | str | datetime | None
|
Lower bound on creation date — epoch-ms |
None
|
creation_timestamp_to
|
int | float | str | datetime | None
|
Upper bound on creation date ( |
None
|
last_access_timestamp_from
|
int | float | str | datetime | None
|
Lower bound on last-access date
( |
None
|
last_access_timestamp_to
|
int | float | str | datetime | None
|
Upper bound on last-access date
( |
None
|
role
|
str | None
|
Filter by role ( |
None
|
order_by
|
str | None
|
Sort field id — mapped to |
None
|
order_desc
|
bool | None
|
Descending sort ( |
None
|
**filters
|
Any
|
Additional snake_case fields forwarded to the request body (converted to
camelCase). Escape hatch for the long-tail |
{}
|
list_raw(req)
¶
POST /admin/data/users with a pre-built request DTO (escape hatch).
me()
¶
GET /core/auth/current-user-data — alias for :meth:AuthAPI.current_user_data.
profile()
¶
GET /core/user-profile/info — own profile (distinct from :meth:me).
Facade Reference¶
pynteracta.models.facade.users.UserForEdit
¶
Narrow facade over :class:~generated.GetUserForEditResponseDTO.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying generated DTO; access additional fields via this escape hatch. |
Source code in src/pynteracta/models/facade/users.py
account_photo_url
property
¶
URL of the user's current profile photo.
blocked
property
¶
Whether the account is blocked.
contact_email
property
¶
Primary contact email.
external_id
property
¶
External system identifier.
first_name
property
¶
User first name.
last_name
property
¶
User last name.
occ_token
property
¶
Token di concorrenza da passare a edit (spec 05, RF-023a).
from_dict(data)
classmethod
¶
Parse from a raw API response dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict
|
Parsed JSON response body. |
required |
Returns:
| Type | Description |
|---|---|
UserForEdit
|
A new :class: |
Source code in src/pynteracta/models/facade/users.py
pynteracta.models.facade.users.UserWriteResult
¶
Façade sulla risposta di create, edit ed edit_credentials di un utente.
I tre DTO di risposta non hanno gli stessi campi: le proprietà assenti valgono None.
user_id viene dalla risposta di creazione; per le modifiche è quello passato dal
chiamante, perché il server non lo restituisce.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
Il DTO generato sottostante ( |
Source code in src/pynteracta/models/facade/users.py
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 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 | |
account_photo_url
property
¶
URL della foto dell'utente dopo la scrittura.
expired_credentials
property
¶
Se le credenziali custom create vanno cambiate al primo accesso.
generated_password
property
¶
Password custom generata dal server alla creazione, se richiesta.
next_occ_token
property
¶
Token di concorrenza da usare per la modifica successiva.
sent_email_notify
property
¶
Se il server ha inviato l'email di notifica delle credenziali.
user_id
property
¶
Id dell'utente scritto: dalla risposta di creazione, altrimenti quello passato.
from_create(data)
classmethod
¶
Legge la risposta di POST admin/manage/users.
Lo swagger dichiara generatedPassword come lista di stringhe, ma il tenant restituisce
una stringa (prova sul tenant, spec 05): la si normalizza in lista di un elemento. Se la
risposta non ha la forma attesa l'errore riporta solo i nomi dei campi, mai i valori, e
non incatena l'eccezione di pydantic: la password non deve finire in un messaggio di
eccezione (RNF-001).
Source code in src/pynteracta/models/facade/users.py
from_credentials(data, user_id)
classmethod
¶
Legge la risposta di PUT admin/manage/users/{userId}/credentials.
Source code in src/pynteracta/models/facade/users.py
from_edit(data, user_id)
classmethod
¶
Legge la risposta di PUT admin/manage/users/{userId}.
See also the guide Filtering and sorting users.