chapps.models module
CHAPPS Data Validation Models
This module consists of the Pydantic data models required to represent and also communicate about the various database records which control CHAPPS. There are a few types of models, and perhaps more types to come, so some short discussion of what they are and why they are needed seems reasonable.
Representational Models
There are (currently quite simple) objects which control CHAPPS: User objects are at the root of that tree, and they are linked to one (outbound) Quota object each to control how much email they may send. User objects may also be linked to multiple Domain and Email objects, to represent who they are allowed to appear to be while sending email.
FastAPI uses Pydantic for data validation during API execution. It behooves
us to define Pydantic models as representations of the objects, therefore.
This could be considered the front-facing identity of the object, which has a
back-facing identity represented by its database model, defined in
dbmodels
.
A metaclass is defined which implements __getattr__
, in order to allow the
validation model to masquerade as a database model to a certain extent. That
routine expects the validation model to define a subclass called Meta
with a
class attribute called orm_model
which refers to the database model for the
object. In this way, the validation model (class) is empowered to marshall a
set of instances from the database, without a lot of messy dereferencing.
API Response Models
In order to specify to the API constructors and the automatic API documentation generators what the response for a particular API route should look like (contain), more Pydantic models are defined.
All responses contain the CHAPPS version string and UNIX epoch time stamp in them, as well as the response to the query, and possibly optional data regarding an object’s associations. A fair number of response models are defined, and they also fall into a few categories.
Unitary Data Model Responses
When a single object of the primary type is being returned, that object is the
value of the response
key in the object returned by the API. If the object
has associations to objects of other types, the expectation is that a list of
those objects will be returned as the value of a key named for the association,
as if it were to be accessed via the ORM. Those associated objects are listed
without any of their own associations included.
Data Model Listing Responses
These response models are named almost exactly the same as their unitary
counterparts, but with their model names pluralized. They will contain a list
of objects of the relevant type in their response
attributes, without any
associations.
Custom Live Responses
Some of the response models are meant to relay information from the
live
API routes, which deal with the current state of CHAPPS as
reflected in Redis. These are each explained in their own documentation.
Basic Datatype Responses
Some operations return a very simple value, such as an integer or string, and so there are some response models to use in such cases.
- class chapps.models.AssocOperation[source]
-
‘add’, ‘subtract’, or ‘replace’
use ‘replace’ only with unitary associations; logic in
JoinAssoc
which responds to thereplace
operation is designed to work only with scalar values.- add = 'add'
- subtract = 'subtract'
- replace = 'replace'
- class chapps.models.SDAStatus[source]
-
sender-domain auth status: AUTH, PROH, or NONE
- AUTH = 'AUTHORIZED'
- PROH = 'PROHIBITED'
- NONE = 'NOT CACHED'
- class chapps.models.SPFResult[source]
-
SPF check results
- passing = 'pass'
- fail = 'fail'
- temperror = 'temperror'
- permerror = 'permerror'
- softfail = 'softfail'
- none_neutral = 'none_neutral'
- class chapps.models.PolicyResponse[source]
Bases:
object
A wrapper for policy results
- class chapps.models.CHAPPSMetaModel[source]
Bases:
pydantic.main.ModelMetaclass
Metaclass for CHAPPS Pydantic models
We inject an override for
__getattr__()
in order to attempt to find missing attributes on the ORM class attached via theMeta
subclass of each model class. This allows the Pydantic data-model class to serve as a proxy for the ORM class, meaning that we can handle Pydantic models in the API code, and still call ORM methods on them, and cause corresponding ORM objects to be instantiated on demand, etc.
- class chapps.models.CHAPPSModel[source]
Bases:
pydantic.main.BaseModel
Base API data model
All models should define a class called
Meta
and define within it a variable calledorm_model
as a reference to the ORM model class (generally defined indbmodels
) corresponding to the data model. In this abstract superclass, the ORM model reference is to the parallel abstract ORM model superclass.Models also define a class called
Config
, which is used byPydantic
. In it,orm_mode
should be set toTrue
. It is also possible to include additional detail for the OpenAPI documentation parser.All models have these attributes/columns:
- class Meta[source]
Bases:
object
Used by CHAPPS
- orm_model
The ORM model class corresponding to this data model
alias of
sqlalchemy.orm.decl_api.Base
- classmethod wrap(orm_instance)[source]
Wrap an ORM instance in its corresponding Pydantic data model
- Parameters
orm_instance (cls.Meta.orm_model) – an ORM instance of the appropriate type
- Returns
a pydantic model created from an ORM model
- classmethod join_assoc(**kwargs)[source]
Create a
JoinAssoc
with this class as the source- Parameters
assoc_name (str) – attribute name of the association
assoc_type (type) – usually
int
orList[int]
; should be the type for the API to expect when setting up the route metadataassoc_model (DB_Base) – a reference to the dbmodel class of the associated object
assoc_id (str) – label of associated object’s ID column in the join table
table (sqlalchemy.schema.Table) – a reference to the join table schema; it will be a constant in this module, generally
- Return type
This convenience routine for generating a
JoinAssoc
provides the source model and ID-column info as it passes on the other arguments.- Return type
- class chapps.models.User[source]
Bases:
chapps.models.CHAPPSModel
User objects represent entities authorized to send email
- name: chapps.models.ConstrainedStrValue
user identifiers may be from 5 to 127 chars long
- class Config[source]
Bases:
object
- orm_mode = True
- schema_extra = {'example': {'id': 0, 'name': '[user.identifier@]domain.name'}}
- class Meta[source]
Bases:
object
- orm_model
alias of
chapps.dbmodels.User
- class chapps.models.Quota[source]
Bases:
chapps.models.CHAPPSModel
Quota objects represent transmission count limits
- name: Optional[chapps.models.ConstrainedStrValue]
quota labels may be up to 31 chars long
- class Config[source]
Bases:
object
- orm_mode = True
- schema_extra = {'example': {'id': 0, 'name': 'fiftyPerHour', 'quota': 1200}}
- class Meta[source]
Bases:
object
- orm_model
alias of
chapps.dbmodels.Quota
- class chapps.models.Domain[source]
Bases:
chapps.models.CHAPPSModel
Domain objects have a name and ID; the name never contains an
@
- name: Optional[chapps.models.ConstrainedStrValue]
domain names may be up to 63 chars long
- class Config[source]
Bases:
object
- orm_mode = True
- schema_extra = {'example': {'check_spf': True, 'greylist': False, 'id': 0, 'name': '[sub.]domain.tld'}}
- class Meta[source]
Bases:
object
- orm_model
alias of
chapps.dbmodels.Domain
- class chapps.models.Email[source]
Bases:
chapps.models.CHAPPSModel
Email objects have a name and ID; the name always contains an
@
- name: chapps.models.ConstrainedStrValue
unique string label
- class Config[source]
Bases:
object
- orm_mode = True
- schema_extra = {'example': {'id': 0, 'name': 'someone@example.com'}}
- class Meta[source]
Bases:
object
- orm_model
alias of
chapps.dbmodels.Email
- class chapps.models.CHAPPSResponse[source]
Bases:
pydantic.main.BaseModel
Base
Pydantic
model for API responses
- class chapps.models.UserResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a single User record
- response: chapps.models.User
The
response
field contains a User record
- domains: Optional[List[chapps.models.Domain]]
A list of associated Domain records may be included
- emails: Optional[List[chapps.models.Email]]
A list of associated Email records may be included
- quota: Optional[chapps.models.Quota]
The Quota record associated with the User may be included
- class chapps.models.UsersResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a list of User records
- response: List[chapps.models.User]
A list of User objects
- class chapps.models.DomainResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a single Domain record
- response: chapps.models.Domain
A Domain object
- users: Optional[List[chapps.models.User]]
A list of User objects associated to the Domain may be included
- class chapps.models.DomainsResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a list of Domain records
- response: List[chapps.models.Domain]
A list of Domain objects
- class chapps.models.EmailResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a single Email record
- response: chapps.models.Email
An Email object
- users: Optional[List[chapps.models.User]]
A list of associated User objects may be included
- class chapps.models.EmailsResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a list of Email records
- response: List[chapps.models.Email]
A list of Email objects
- class chapps.models.QuotaResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a single Quota record
- response: chapps.models.Quota
A Quota object
- class chapps.models.QuotasResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a list of Quota records
- response: List[chapps.models.Quota]
A list of Quota objects
- class chapps.models.IntResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with an integer
- class chapps.models.FloatResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a float
- class chapps.models.TextResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responding with a string
- class chapps.models.TimeResp[source]
Bases:
chapps.models.FloatResp
Data model for responding with a UNIX epoch time value
- class chapps.models.InstanceTimesResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for returning a list of instances and timestamps
- class chapps.models.LiveQuotaResp[source]
Bases:
chapps.models.CHAPPSResponse
Data model for responses from the Live API
- class chapps.models.SourceUserMapResp[source]
Bases:
chapps.models.CHAPPSResponse
- A source-user map is a dict-of-dicts:
top level key is domain or email name
second key is user
value is SDAStatus
- response: Dict[str, Dict[str, chapps.models.SDAStatus]]
A map of auth-subject to dicts of username mapping to status
- class chapps.models.BulkQuotaResp[source]
Bases:
chapps.models.CHAPPSResponse
Maps User
name
onto Quotaid
With descriptive labels and optional remarks (from the live API)
- class chapps.models.BulkDomainsResp[source]
Bases:
chapps.models.CHAPPSResponse
Maps User
name
onto lists of Domainid
With descriptive labels and optional remarks (from the live API)
- class chapps.models.BulkEmailsResp[source]
Bases:
chapps.models.BulkDomainsResp
Maps User
name
onto lists of Emailid
With descriptive labels and optional remarks (from the live API)
- class chapps.models.DeleteResp[source]
Bases:
chapps.models.TextResp
Data model for responding to deletion requests