chapps.rest.routers.users module
User record management implemented by factories
This module defines API routes for managing User records, and defines the JoinAssoc
data to describe the relationship between User records and other record types: Domain, Email, and Quota.
As such, this is the only router where the factories are used to create or update records with multiple associations. It seems a good opportunity for another example.
- chapps.rest.routers.users.api = <fastapi.routing.APIRouter object>
The API router for User record maintenance
This router is once again full of calls to the factories in the
common
module. The User model is the most connected to other things, however, and so seems like a good spot for examples related to associations.Creating Users
When creating a User record, it seems likely that the caller might like to automatically associate the new User with an existing Quota record, and at least one Domain record, perhaps even an Email record. The factory will provide a coroutine which will optionally accept ID lists for these associations. That is to say, the coroutine will treat them as optional arguments and do nothing if they are not provided.
All of the logic and magic behind making this go smoothly is hidden within the
JoinAssoc
class. We simply provide a list of these associations to the factory and it handles the rest:api.post( "/", status_code=201, response_model=UserResp, responses={status.HTTP_409_CONFLICT: {"description": "Unique key error."}}, )(create_item(User, response_model=UserResp, assoc=user_join_assoc))
In the above example, the FastAPI code for specifying details about the POST route takes up more space than the factory call to obtain the actual User creation coroutine.
The definition of
user_join_assoc
may be found below. It is a list containing references to all threeJoinAssoc
instances, relating to a Quota and lists of Domain and Email records.Handling Associations
Sometimes there is a need to remove a specific association from a list, or add one or a handful. It would be helpful if it were not necessary to obtain or manufacture a list of IDs in order to use a replacement-type edit such as the basic model update route. The User model has a number of different associations to manage, so here is an example of adding domains:
api.put("/{item_id}/domains/", response_model=TextResp)( adjust_associations( User, assoc=[user_domains_assoc], assoc_op=AssocOperation.add ) )
I chose to use PUT because it is associated with partial updates. Within the API router wrapper, we use a call to the
adjust_associations()
route factory, which returns a coroutine which will take a User ID and a list of Domain IDs as arguments. When invoked via the API, that coroutine will ensure that all the existing Domain records listed are associated to the User.IntegrityError
is ignored during the process, so any attempts to add an existing association or to add a nonexistent Domain will not raise errors – all existing Domain records identified by ID will be associated to the User, and other associations to that User will be preserved.- Parameters
scope (MutableMapping[str, Any]) –
receive (Callable[[], Awaitable[MutableMapping[str, Any]]]) –
send (Callable[[MutableMapping[str, Any]], Awaitable[None]]) –
- Return type
None
- async chapps.rest.routers.users.map_usernames_to_quota_ids(user_ids)[source]
Map User identfiers onto Quota ids
If a display requires a large matrix of users with their quota settings, this routine may be helpful. The Quota records may be fetched before or after, just once for each kind of quota, and then cross-referenced much more efficiently than requesting each separately.
The
response
contains a list of JSON objects (hashes or dictionaries), with the keysuser_name
andquota_id
. Only existing users are returned, possibly withquota_id
set toNone
if the user has no quota policy assigned. They are sorted by the user’s ID value.
- async chapps.rest.routers.users.map_usernames_to_domain_ids(user_ids)[source]
Map User identfiers onto Domain id lists
If a display requires a large matrix of users with their domain authorizations, this routine may be helpful. The Domain records may be fetched before or after, just once for each domain, and then cross-referenced much more efficiently than requesting each separately.
The
response
contains a list of JSON objects (hashes or dictionaries), with the keysuser_name
anddomain_ids
. Only existing users are returned, possibly withdomain_ids
set toNone
if the user has no domain authorizations. They are sorted by the user’s ID value.
- async chapps.rest.routers.users.map_usernames_to_email_ids(user_ids)[source]
Map User identfiers onto Email id lists
If a display requires a large matrix of users with their email authorizations, this routine may be helpful. The Email records may be fetched before or after, just once for each email, and then cross-referenced much more efficiently than requesting each separately.
The
response
contains a list of JSON objects (hashes or dictionaries), with the keysuser_name
andemail_ids
. Only existing users are returned, possibly withemail_ids
set toNone
if the user has no email authorizations. They are sorted by the user’s ID value.