Repository navigation
User Account Management API
Accessor: server.user
Reference: https://docs.tak.gov/api/takserver#tag/file-user-account-management-api
This API manages file-based user accounts and groups: create, update, delete, bulk-generate users, and read or replace group memberships.
Warning
Server quirk (5.7-RELEASE-43-HEAD): the endpoints below that accept
group lists (create_or_update_file_user, create_file_users_in_bulk,
update_users_for_group, update_groups_for_user) answer with
HTTP 500 when any of the three group-list fields is omitted from
the JSON body. The wrapper therefore always sends all three fields,
using empty lists [] for those you do not pass. You normally never
notice this - but if you call the raw API yourself, always include
groupList, groupListIN and groupListOUT.
Tip
Groups are implicit: there is no create-group endpoint. A group
appears automatically as soon as a user carries it (via
create_or_update_file_user, create_file_users_in_bulk or the
update_* operations) and disappears again once no user has it. To
create a group, just create a user with that group - to delete it,
remove it from all users. get_users_in_group() on a group nobody has
returns HTTP 400, so check get_all_group_names() first.
Note
Direction semantics - IN and OUT are from the group's point of view, not the user's:
-
groupListIN- groups the user may send into (the writer side; a feed producer holds its feed group as IN, e.g. an ADSB feeder with the matching*_WRITEentitlement) -
groupListOUT- groups whose traffic the user receives (the reader side; a consumer holds a feed channel as OUT) -
groupList- both directions at once
async def create_or_update_file_user(
username: str,
password: str,
group_list_both: list[str] | None = None,
group_list_in: list[str] | None = None,
group_list_out: list[str] | None = None,
) -> tuple[int, Any]Creates or updates a file-based user account. If the username already exists, its password and group membership are updated.
API: POST /user-management/api/new-user
| Parameter | Type | Description |
|---|---|---|
username |
str |
Username for the new/existing user |
password |
str |
Password (the server enforces a password complexity policy: minimum 15 characters, must contain upper- and lowercase letters, a digit and a special character) |
group_list_both |
list[str] or None
|
Groups for both directions (API field groupList) |
group_list_in |
list[str] or None
|
Groups the user may send INTO (API field groupListIN) |
group_list_out |
list[str] or None
|
Groups whose traffic the user RECEIVES (API field groupListOUT) |
Returns: (status_code, response)
Example:
# an analyst receives feed traffic but may not write into feeds
status, data = await srv.user.create_or_update_file_user(
username="analyst",
password="Strong-Pw-9!",
group_list_out=["default"],
)async def get_all_users() -> tuple[int, Any]Returns a list of all users registered on the server.
API: GET /user-management/api/list-users
Returns: (status_code, list_of_users) — each user is a dict with fields such as username, groups, etc.
Example:
status, users = await srv.user.get_all_users()
if status == 200:
for u in users:
print(u["username"])async def get_all_group_names() -> tuple[int, Any]Returns a list of all group names defined on the server.
API: GET /user-management/api/list-groupnames
Returns: (status_code, list_of_groups) — each entry is a dict with a groupname field.
Example:
status, groups = await srv.user.get_all_group_names()
if status == 200:
for g in groups:
print(g["groupname"])async def get_users_in_group(group: str) -> tuple[int, Any]Returns the members of a single group.
API: GET /user-management/api/users-in-group/{group}
| Parameter | Type | Description |
|---|---|---|
group |
str |
Group name |
Returns: (status_code, SimpleGroupWithUsersModel) — a dict with
groupname and the user-list fields (usersInGroupList,
usersInGroupListIN, usersInGroupListOUT).
Example:
status, group = await srv.user.get_users_in_group("__ANONYMOUS__")
if status == 200:
print(group["groupname"], group["usersInGroupList"])async def get_groups_for_user(username: str) -> tuple[int, Any]Returns the groups a single user belongs to.
API: GET /user-management/api/get-groups-for-user/{username}
| Parameter | Type | Description |
|---|---|---|
username |
str |
Username |
Returns: (status_code, SimpleUserGroupModel) — a dict with
username and the group-list fields (groupList, groupListIN,
groupListOUT).
Example:
status, model = await srv.user.get_groups_for_user("analyst")
if status == 200:
print(model["groupList"])async def change_user_password(username: str, password: str) -> tuple[int, Any]Changes a user's password without touching group membership.
API: PUT /user-management/api/change-user-password
| Parameter | Type | Description |
|---|---|---|
username |
str |
Username |
password |
str |
New password (same complexity policy as above) |
Returns: (status_code, response)
Example:
status, _ = await srv.user.change_user_password("analyst", "Newer-Pw-9!")async def delete_user(username: str) -> tuple[int, Any]Deletes a user account.
API: DELETE /user-management/api/delete-user/{username}
| Parameter | Type | Description |
|---|---|---|
username |
str |
Username to delete |
Returns: (status_code, response)
Example:
status, _ = await srv.user.delete_user("analyst")Caution
there is no undo. Deleting a user removes its accounts, certificates and memberships.
async def create_file_users_in_bulk(
username_expression: str,
start_n: int,
end_n: int,
group_list: list[str] | None = None,
group_list_in: list[str] | None = None,
group_list_out: list[str] | None = None,
) -> tuple[int, Any]Generates a range of users in one call. The expression must contain the
literal placeholder [N], which is replaced by each number from
start_n to end_n (inclusive). This is handy for exercise rosters or
drill groups.
API: POST /user-management/api/new-users
| Parameter | Type | Description |
|---|---|---|
username_expression |
str |
Username pattern, must contain [N], e.g. "drill-[N]"
|
start_n |
int |
First number substituted into [N]
|
end_n |
int |
Last number substituted into [N]
|
group_list |
list[str] or None
|
Groups for both IN and OUT (API field groupList) |
group_list_in |
list[str] or None
|
Groups the user may send INTO (API field groupListIN) |
group_list_out |
list[str] or None
|
Groups whose traffic the user RECEIVES (API field groupListOUT) |
Returns: (status_code, list_of_UserPasswordModel) — one dict per
generated user with username and password (the server generates the
passwords itself and returns them exactly once).
Example:
status, accounts = await srv.user.create_file_users_in_bulk(
username_expression="drill-[N]",
start_n=1,
end_n=3,
group_list=["__ANONYMOUS__"],
)
if status == 200:
for account in accounts:
print(account["username"], account["password"])The bulk endpoint rejects requests without a non-empty
group_list(HTTP 400, "No new user was created").
async def update_users_for_group(
groupname: str,
users_in_group_list: list[str] | None = None,
users_in_group_list_in: list[str] | None = None,
users_in_group_list_out: list[str] | None = None,
) -> tuple[int, Any]Replaces the user membership of a group.
API: PUT /user-management/api/update-group-users
| Parameter | Type | Description |
|---|---|---|
groupname |
str |
Group whose membership to replace |
users_in_group_list |
list[str] or None
|
Users for both IN and OUT (API field usersInGroupList) |
users_in_group_list_in |
list[str] or None
|
Users who may send INTO the group (API field usersInGroupListIN) |
users_in_group_list_out |
list[str] or None
|
Users who RECEIVE the group's traffic (API field usersInGroupListOUT) |
Returns: (status_code, response)
Example:
status, _ = await srv.user.update_users_for_group(
groupname="drill",
users_in_group_list=["drill-1", "drill-2"],
)async def update_groups_for_user(
username: str,
group_list: list[str] | None = None,
group_list_in: list[str] | None = None,
group_list_out: list[str] | None = None,
) -> tuple[int, Any]Replaces the group membership of a user.
API: PUT /user-management/api/update-groups
| Parameter | Type | Description |
|---|---|---|
username |
str |
User whose membership to replace |
group_list |
list[str] or None
|
Groups for both IN and OUT (API field groupList) |
group_list_in |
list[str] or None
|
Groups the user may send INTO (API field groupListIN) |
group_list_out |
list[str] or None
|
Groups whose traffic the user RECEIVES (API field groupListOUT) |
Returns: (status_code, response)
Example:
status, _ = await srv.user.update_groups_for_user(
username="analyst",
group_list=["default"],
)async def user_exists(user: str) -> boolChecks if a specific username exists on the server.
| Parameter | Type | Description |
|---|---|---|
user |
str |
Username to look up |
Returns: True if a matching user exists, False otherwise.
Internally calls get_all_users() and searches by username field.
Note
If the underlying request fails (non-200 response), user_exists()
returns False rather than raising - it cannot distinguish "absent"
from "server error". Call get_all_users() yourself if you need to
tell those cases apart.
async def group_exists(group: str) -> boolChecks if a specific group name exists on the server.
| Parameter | Type | Description |
|---|---|---|
group |
str |
Group name to look up |
Returns: True if a matching group exists, False otherwise.
Internally calls get_all_group_names() and searches by groupname field.
Note
As with user_exists(), a failing request yields False, not an
exception.