There are a variety of ways that you can move information into and out of interview sessions, besides obtaining information from the user.
URL arguments
As explained in the invocation section, when a user starts an
interview, the user visits a URL. This URL can contains parameters of
your own choosing (as long as the names do not conflict with any of
the reserved URL parameters). Data passed using these parameters is
available inside the interview session using the url_args
special
variable.
You can also change the url_args
during an active interview
session. If the user’s browser is logged into a session, and the user
clicks on a hyperlink to the same interview with URL parameters set,
the url_args
will be updated.
Using the “actions” system
The normal flow of an interview in docassemble is as follows:
- The screen loads, and the user sees whatever
question
is the next step in the interview logic, given the current state of the interview answers. - The user enters some information (if the screen asks for information) and then presses a button.
- The interview answers are updated with the new information.
- Go back to step 1.
Eventually, the interview will reach a logical endpoint. This flow makes sense for the main path of the interview, but sometimes the user needs to deviate from the main path. For example, they might want to adjust their answers to previous questions.
In docassemble, “actions” are used to trigger deviations from the
main path of the interview logic. For example, suppose that under
the main path of the interview logic, the next piece of
information that is necessary to gather is favorite_legume
. The
interview will show a question
that offers to define
favorite_legume
. But suppose you want the user to be able to go
back to the favorite_vegetable
question. (Perhaps a common mistake
is for users to list a legume as their favorite vegetable). You can
allow the user to launch an “action” that causes the interview to seek
(or in this case, re-seeks) the variable favorite_vegetable
instead of
the variable favorite_legume
.
For more information about “actions,” see the documentation for
url_action()
and url_ask()
.
Another type of deviation from the main interview logic is a background action. This is where some code runs on the server, in the background, where the user can’t see anything. This is typically used for code that takes a long time to run, where you don’t want the user to have to wait for the result, or there is a danger that the user’s browser will time out if the server does not respond quickly enough.
Pushing information into a session
Typically, users launch actions by clicking hyperlinks within the docassemble application. However, it is also possible to click hyperlinks outside of the application that run actions inside the session.
For more information about this feature, see the
interview_url_action()
function. This function creates a URL that
embeds the session ID.
Pulling information out of a session
The interview_url_action()
function also allows the extraction of
information from an interview. You can call
interview_url_action()
with a reference to an event
that runs
json_response()
to return selected information in a
machine-readable format. This allows you to create a customizable
“API” for your interview.
If you go through the interview and obtain the URL, you can try loading it in a different browser to verify that another application (not having the same browser cookies) can access the information in JSON format.
Using the API
You can also manipulate interview sessions using the docassemble API.
Sending e-mail from a session
You can use the send_email()
function to send e-mails from an
interview session to the outside world. You will first need to
configure your server to
send e-mail.
Sending e-mail to a session
If you are using Docker to deploy your server, and you have configured your server to receive e-mail, you can use docassemble’s e-mail-to-session feature.
This involves generating a special e-mail address using
interview_email()
. Any e-mails sent to that address and received
by the server will be processed and made available in the interview
session for retrieval using get_emails()
.
Sending text messages from a session
You can use the send_sms()
function to send text messages from an
interview session to the outside world. You will first need to
configure your server to
send text messages. Despite the function name (“SMS”), this function
can be used to send messages through Twilio’s WhatsApp API.
Persisting data
Persistent interview sessions
The interview answers in an interview session are stored in encrypted form inside of rows in a SQL table. Documents are stored on the server or in a cloud storage system. If a user who is not logged in completes an interview, they will not be able to access their interview session again after closing their browser, because the encryption key will be lost. However, if they log in, their interview session will be tied to their account, and their password will become the decryption key for the session.
The encryption of interview answers makes it impossible for someone
other than the original user to access the data in the interview
session, unless the decryption key (the user’s password) is known.
However, if the interview sets multi_user
to False
, then
functions like interview_url_action()
can be used to access the data
in the interview as long as the interview session exists.
By default, interview sessions are deleted after 90 days of
inactivity. This feature can be modified or turned off using the
interview delete days
configuration directive.
Persistent files
When an interview session is deleted, the files associated with the interview session are also deleted.
If you want a file to continue exist after its associated interview
session has been deleted, you can use the .set_attributes()
method
of the DAFile
object in order to indicate that the file should not
be deleted when the interview session is deleted.
Saving to SQL
A session’s interview answers are stored in a SQL server, but not in a
way that is easily accessible across interview sessions. Interview
sessions are not persistent; the user can delete a session, and a
session may be deleted due to inactivity (unless the interview
delete days
configuration directive is set to disable automatic
deletion).
If you want to save information in SQL in a way that will persist
indefinitely and that will not be encrypted, you can use the
store_variables_snapshot()
function to store the interview answers
to a special SQL table in a JSON format that allows you to write SQL
queries that access individual variables inside the data structure.
You can also use write_record()
, delete_record()
and
read_records()
functions to store data (including Python objects)
in SQL records. These methods do not preserve server-side encryption,
however.
You can save information in encrypted form in SQL in a Redis-like
fashion using a DAStore
object.
It is also possible for DAObject
s to “mirror” rows in a SQL
database. To do this, you need to write custom classes that are
subclasses of DAObject
and the special object SQLObject
. For
more information, see the documentation for SQLObject
.
Saving to Redis
Instead of saving to the SQL database, you can write persistent data
to Redis using an instance of the DARedis
object.
Using third-party APIs
Your interview can also communicate with the outside world using any Python module that provides the functionality you want.
Here is a simple example that calls the World Clock API to obtain the current time (which you don’t really need an API to do).
The API call is in a Python module called gettime.py
in the
docassemble.demo
package. The contents of this file are:
The World Clock API returns output in JSON format, such as:
The get_time()
function uses the requests
library. The variable
r
represents the response of the World Clock API’s server to the
attempt to your code’s attempt to obtain the contents of the given
URL. This object has a handy method .json()
that converts the
output of the request to a data structure, assuming that the request
returns JSON. The get_time()
function returns the
currentDateTime
part of the World Clock API’s response.
Here is an interview that calls the get_time()
function:
For more complex examples, see the sample interviews in the documentation that read data from a Google Sheet and write data to a Google Sheet.
Sharing information across sessions
Users’ answers to questions in an interview are stored in the
“interview answers,” which is a pickled Python dictionary stored on
the SQL server. Each set of “interview answers” is specific to a
particular interview (e.g.,
docassemble.demo:data/questions/questions.yml
) and specific to a
particular session in that interview (e.g., session ID
BoJSwJHppIPFYtFEOeBU1y4koaM3L9zP
).
Every time the user proceeds from one screen to another, the interview answers are changed, the interview logic is evaluated (which may change the interview answers further) and a new set of interview answers is saved. The user can incrementally “undo” changes to the interview answers by pressing the “back” button, which restores an earlier saved state of the interview answers.
docassemble’s interview logic system is based on this system of
the “interview answers.” If the interview logic calls for a value of
a variable that is undefined, docassemble will ask a question
or
run code
to obtain a definition of that variable. docassemble
asks for information that is missing in the interview answers.
By default, the interview answers are encrypted on the server and can only be accessed when the user provides the decryption key via a web browser cookie. This gives the user control over their information.
The way that docassemble works with interview answers is very different from the way that a typical web-based database works with data. A web-based database will typically use a SQL backend, where the front end allows the user to populate fields of data records, where the fields are columns and the data records are rows in SQL tables. These applications are known as “CRUD” applications, because the front end facilitates creating, retrieving, updating, and deleting rows in tables. In docassemble, by contrast, the interview answers are not values in two-dimensional data tables, but rather Python data structures that at any point in time may be only be partially populated.
If you want to share information across sessions, you can do so, but the methods for doing so are not going to be the same as the methods for accessing data in a CRUD application.
There are multiple ways that you can share information across sessions:
- Push data: from session A, you can populate variables in session B
by calling
set_session_variables()
. If session B does not exist yet, you can first initiate it by callingcreate_session()
. - Pull data: from session B, you can retrieve variables from session A
by calling
get_session_variables()
. - Initialize variables from values stored in a common storage area:
from session A, you can use a
DAStore
object to save data to a storage area that is specific to the user but can be accessed from any session. In session B, you can writecode
blocks that initialize variables to values that are stored in that storage area, if the storage area exists. By default, data are encrypted using the same encryption system as interview answers, and encryption can be turned off. - Share global variables across sessions: in session A, you can use a
DAGlobal
object to store the part of the interview answers you want to share. In session B, you can use aDAGlobal
object with the same “base” and “key,” and the attributes of the object in both sessions will be stored in a common storage area rather than in the interview answers of either session. Encryption is not available with this option. - Share data using Redis:
DARedis
can also be used as a storage area. From session A, you can use the.set_data()
method ofDARedis
to save a Python data structure to Redis, and then inside of session B, you can call the.get_data()
method ofDARedis
to retrieve the data structure. Redis is a fast, in-memory data storage area, so it is best used with information that only needs to be stored temporarily. Encryption is not available. - Share data in a list of records: the
write_record()
andread_records()
functions are useful for storing lists of data records, where each list is identified by a key that is global to the server. Inside of session A, you can callwrite_record()
to store a row in a list. Inside of session B, you can callread_records()
to retrieve all of the records in that list. Encryption is not available. - Sync data to a SQL database: if you would like to use a traditional
SQL database as a “single source of truth” for variables in your
interview, you can use the
SQLObject
system. This allows you to “sync” variables in your interview answers with a SQL database. Encryption is not supported. - Stash data temporarily in an encrypted data store: from session A,
you can call
stash_data()
to store particular interview answers in an encrypted location.stash_data()
returns tokens that can be used to access the stashed data. Session A can offer the user URLs to other interviews, in which the tokens are URL parameters. If the user clicks one of these URLs and starts session B, the interview logic in session B can get look for the tokens inurl_args
and callretrieve_stashed_data()
to retrieve the interview answers that had been stored by session A. The stored data can be deleted once they are retrieved, and can automatically expire after a period of time. This is a secure way to pass data from one session to another. It avoids storing human-readable information in the URL parameters when passing data from one session to a prospective session. It avoids the unnecessary creation of a new session if the user does not want to proceed to start a new session. The encryption system is independent of the encryption system for interview answers, so that knowledge of the tokens does not lead to knowledge of any interview answers. There are API interfaces for stashing data and retrieving stashed data.