The script cfgagent.py (or cfgagent.cgi) persistently stores information about agents and licenses, and is the official interface by which all agent/license information is configured in the CEStatus module. When called as a CGI, the script will generally use the GET CGI method (so as to produce a replicable URI). By its design, cfgagent.py can also easily be used for local access to agent/license information, for example in the case where a batch initialization of agent/license data comes from a pre-existing data source.
cfgagent.py allows a few variations in calling details. What is documented in the below syntax diagram is the command-line version of a call, which is the most general version. This type of call may be performed via CGI by URL-encoding the address, e.g.
The equivalent instruction generated by an HTML GET method form would be:
Either of these calling conventions, and also a POST method HTML form containing the same data, will produce identical modifications to the agent data storage.
Calls to cfgagent.py should obey the following syntax (adjusting for allowed call styles):
[python] cfgagent.py [PERMISSION=<useridstring>] SSN=<ssn> [DELETE] [FIRSTNAME=<firstname>] [MIDNAME=<middlename>] [LASTNAME=<lastname>] [BIRTHDATE=<birthdate>] [ [LICINFO=<stateabbrev>:<line>[:<licensenum>[:<issuedate>]]] [...] ] [HOME1=<addressline1>] [HOME2=<addressline2>] [HOMECITY=<city> [RESSTATE=<residentstate>] [OFFICE1=<addressline1>] [OFFICE2=<addressline2>] [OFFICECITY=<city> [OFFICESTATE=<residentstate>]
All keywords are case insensitive, but are listed in the syntax diagram in upper case for visual distinction. Order of arguments does not matter.
If the LICINFO keyword is specified, a few special rules apply to its
compound value. The components of LICINFO are separated by colons. A
stateabbrevmust be provided first, followed by a mandatory
linemay have the special value
None; if this value is used, all the license information for the
specified state is removed from the agent record. If a regular value is
line, the new
lineis added to the list
of lines held in the specified state.
issuedateare both optional components. Any values provided will
overwrite any previously stored value, if such exist. Due to the order of the
components, it is not possible to modify/create an
issuedatewithout also providing
same call. In practice, this limitation is of little significance.
As is indicated in the syntax diagram, multiple occurances of the LICINFO keyword may occur. These occurances may specify license information in multiple states, and/or may be used to specify multiple license lines within a state. For example, the below is a legal call:
cfgagent.py SSN=111-11-1111 LICINFO=ma:health LICINFO=ma:life LICINFO=ct:life
However, it should be noted that cfgagent.py is not guaranteed to handle multiple instance of the LICINFO field within an HTML form correctly. It is best, when designing a web-browser interface to cfgagent.py to generate multiple requests, each with a single LICINFO field. A wrapper CGI around the actual cfgagent.py script can also be used to provide a command-line (URL-encoding) style call. The below series of calls will cummulatively have an effect identical to the above use of multiple occurances of LICINFO:
http://gnosis.cx/cfgagent.cgi?SSN=111-11-1111&LICINFO= ma:healthhttp://gnosis.cx/cfgagent.cgi?SSN=111-11-1111&LICINFO= ma:lifehttp://gnosis.cx/cfgagent.cgi?SSN=111-11-1111&LICINFO=ct:life
The DELETE keyword causes the entire agent record with the specified SSN to be removed from the data storage. It makes no sense practically to specify any additional optional keywords when the DELETE keyword is used.
The keyword PERMISSION is reserved for future use, but has no effect at present. In the future, this keyword may be used as part of an access control system.
The semantics of cfgagent.pycalls are more restricted than the syntax itself indicates. That is, some parameter lists which are syntactically valid, may nonetheless return an error message if run. The chief cause of such an error return is if one or more required fields in a call are omitted, which prevents the indicated data from being stored persistently. The semantic validity of a call will depend, in many cases, on previous calls (and therefore on existing data state). If all required fields were indicated on an initial call, subsequent "update" calls need not specify the values of unchanged fields. Key fields, however, must be specified in all cases, and this is indicated in the syntax diagram itself. For a clarification of required and optional fields, consult the below Object Model documentation
The object model of CEStatus is largely identical to the syntax diagram for
cfgagent.py calls. Agents are OOP objects which hold bundles of data,
some of which are themselves objects. Objects at the various levels may have
methods among their attributes. The below hierarchical diagram shows the
structure of an agent object and its dependents. Also indicated is the
mutability and requirement of each object attribute. Key fields are, of
course, required and immutable. In general, unless otherwise indicated, all
non-key data members are mutable, if only because entry mistakes are possible
(update of fields is still controlled by selective access permissions). The
following symbols are used for visual identification of elements (ellipses are
used to indicate held objects whose type may occur multiple times):
|Object||Ordinary Data Member||Method||Key Data Member||Immutable Data Member||Required|
Two features of the CEStatus development language, Python, make the below object model a natural representation of agent/state licensing requirements. One is the dynamic attribution of Python. Optional data members need not be pre-defined with initial placeholder values, but may simply be added as needed. In the OOP parlance of C++ or Java, every Python class is a sort of container class. Second - and probably most importantly - Python provides a facility for persistent storage of objects (class instances) in a manner which allows for reimplementation of methods when those objects are used later (or by other processes). For our purposes, this has the nice property that we can change the business logic of calculating individual state requirements, even while this logic is implemented as a method of a stored object. Once the object is re-read from disk, it takes on the brand new method logic.