Overwatch Web App Package (overwatch.webApp
)¶
General information from the README is available immediately below. Further module specific documentation is available further below in the package reference, with the modules listed below.
Package reference¶
overwatch.webApp.auth module¶
Contains auth functions.
For user authentication, https://exploreflask.com/users.html was extensively used as a guide.
-
class
overwatch.webApp.auth.
User
(username, password)[source]¶ Bases:
flask_login.mixins.UserMixin
A basic user class to manage authentication.
Inherits from
UserMixin
, which implements a basic class for use withlogin_manger()
.New users should be added into the external config file. This class provides no ability to store new users dynamically and assumes that passwords passed to it are already hashed by
bcrypt.generate_password_hash(password, BCRYPT_LOG_ROUNDS)
.The
login_manager
stores this class to manage users.Note
There are also a few attributes inherited from UserMixin
Parameters: - username (str) – Username of new user
- password (str) – Hashed password of new user. Password should be hashed with
bcrypt.generate_password_hash(desiredPassword, BCRYPT_LOG_ROUNDS)
-
users
¶ Contains all valid users with hashed passwords. Loaded from an extra config file.
Type: dict
-
id
¶ The username of the instance of the object
Type: str
-
password
¶ The password of the instance of the object. Note: This must be hashed by the user before passing to this object!
Type: str
-
checkPassword
(plainTextPassword)[source]¶ Check a plain text password against a hashed password.
Parameters: plainTextPassword (str) – The plain text password to test. Returns: True if the password matches the instance of the user. Return type: bool
-
static
getUser
(username, db)[source]¶ Retrieve the username and password of a user.
Used by
load_user()
to maintain a logged in user session.Parameters: username (str) – Username to retrieve Returns: - Returns an instance of the
User
class if the user exists. Otherwise, it - returns
None
.
Return type: User
- Returns an instance of the
-
overwatch.webApp.auth.
authenticateUser
(username, password, db)[source]¶ Checks whether the user credentials are correct.
Parameters: - username (str) – username of the attempted user.
- password (str) – plain text password of the attempted user.
Returns: - If the credentials were valid, an instance of the
User
class is returned so that the login_manager can store that object and track which user is logged in. Otherwise, it returns
None
.
Return type: User
overwatch.webApp.routing module¶
Contains routing functions.
Contains functions to ensure safe routing and redirection of the next URL. These functions are from http://flask.pocoo.org/snippets/62/, and were written by the author of Flask.
Slight modifications were made to redirectBack()
to ensure that a login-logout loop was avoided
under particular circumstances.
-
overwatch.webApp.routing.
getRedirectTarget
()[source]¶ Extracts the Next target and checks its safety.
Note
Relies on the flask.request object.
Parameters: None – Returns: URL if the target is safe. Return type: str
-
overwatch.webApp.routing.
isSafeUrl
(target)[source]¶ Checks URL for safety to ensure that it does not redirect unexpectedly.
Note
Relies on the flask.request object.
Parameters: target (str) – URL for the target to test. Returns: True if the URL is safe. Return type: bool
-
overwatch.webApp.routing.
redirectBack
(endpoint, **values)[source]¶ Handles safe redirection.
It extracts the value of Next from flask.request. If the target is not safe, then redirect back to
endpoint
instead.Note
Relies on the request.form dict.
Parameters: - endpoint (str) – Where to redirect in case the Next url is not safe
- **values (dict) – Arguments to pass to url_for() in case of needing to redirect to endpoint instead.
Returns: - Redirect is called on the next URL if it is safe. Redirects to the
given endpoint if the URL is not safe.
Return type: redirect to NextUrl
overwatch.webApp.utilities module¶
Web app specific utilities.
In particular, it handles tasks related to deployment and minimization which are not relevant to other Overwatch packages.
-
class
overwatch.webApp.utilities.
PolymerBundler
(**kwargs)[source]¶ Bases:
webassets.filter.ExternalTool
Filter to bundle Polymer html imports into a single file for deployment.
Best practices dictate that the Polymer html imports should be combined into a single file to reduce the number of individual http requests. Polymer provides a tool to do so, called
polymer-bundler
. By taking advantage ofwebassets
, we can automatically combine and minimize these files when starting a web app deployment.To successfully define the filter, the following details must be addressed:
- polymer-bundler must only be executed with relative paths, so we cannot use
ExternalTool.subprocess
, since that gives absolute paths. - To ensure that the polymer components also work when not bundled, the filter must be executed in a directory above the static dir.
These issues causes quite some complications! See the
input(...)
function for how to deal with these issues.When
webassets
is run in debug mode, this filter will not be run! Instead, the standard (un-minified) version will be included. For information on forcing this filter to be run, see the web app README.-
input
(_in, out, **kwargs)[source]¶ Plugin function for adding an external filter to
webassets
.As of August 2018, the
kwargs
options available include:kwargs = {'output': 'gen/polymerBundle.html', 'output_path': '/pathToOverwatch/overwatch/webApp/static/gen/polymerBundle.html', 'source_path': '/pathToOverwatch/overwatch/webApp/static/polymerComponents.html', 'source': 'polymerComponents.html'}
Note
polymer-bundler
parses arguments a bit strangely - values such as paths still need to be in a separate argument. Thus, the arguments looks more split than would usually be expected.Parameters: - _in (StringIO) – Input for the filter. Not used here.
- out (StringIO) – Output for the filter. The output for
polymer-bundler
is written here. This will eventually be written out to a file. - **kwargs (dict) – Additional options required to run the filter properly. See the function description for the available options.
Returns: None
-
method
= False¶
-
name
= 'PolymerBundler'¶
-
open
= None¶
-
output
= None¶
- polymer-bundler must only be executed with relative paths, so we cannot use
overwatch.webApp.validation module¶
Contains validation functions.
These functions are important to ensure that only valid values are passed to the processing functions. Validation could likely be improved by moving WTForms, which Overwatch already depends upon for CSRF protection.
-
overwatch.webApp.validation.
convertRequestToPositiveInteger
(paramName, source)[source]¶ Converts a requested parameter into a positive integer.
This function is somewhat similar to the other conversion and validation functions, although it is a bit simpler.
Parameters: - paramName (str) – Name of the parameter in which we are interested in.
- source (dict) – Source of the information. Usually request.args or request.form.
Returns: The requested int or 0 if it was somehow invalid.
Return type: int
-
overwatch.webApp.validation.
convertRequestToPythonBool
(paramName, source)[source]¶ Converts a requested parameter to a python bool.
The validation is particularly useful for jsRoot and ajaxRequest. Note that this function is fairly similar to convertRequestToStringWhichMayBeEmpty.
Parameters: - paramName (str) – Name of the parameter in which we are interested in.
- source (dict) – Source of the information. Usually request.args or request.form.
Returns: True if the retrieved value was True.
Return type: bool
-
overwatch.webApp.validation.
convertRequestToStringWhichMayBeEmpty
(paramName, source)[source]¶ Handle strings which may be empty or contain “None”.
This validation is particularly useful for validating hist names and hist groups request strings to ensure that they are valid strings before doing further validation. Empty strings should be treated as
None
. TheNone
strings are from the timeSlicesValues div on the runPage. Note that this function is fairly similar to convertRequestToPythonBool.Parameters: - paramName (str) – Name of the parameter in which we are interested in.
- source (dict) – Source of the information. Usually request.args or request.form.
Returns: Validated string or
None
if the string is empty or “None”.Return type: str or None
-
overwatch.webApp.validation.
extractValueFromNextOrRequest
(paramName, source)[source]¶ Extract the selected parameter from the next parameter or directly from the request.
First attempt to extract the named parameter from the next parameter in the args of the request. If it isn’t available, then attempt to extract it directly from the request args parameters. This is particularly useful for logging the user back in the case of a default username.
Parameters: - paramName (str) – Name of the parameter to extract.
- source (dict) – Source of the information. Usually request.args or request.form.
Returns: Value of the extracted parameter.
Return type: str
-
overwatch.webApp.validation.
retrieveAndValidateTimeSlice
(subsystem, error)[source]¶ Retrieves the time slice key and then returns the corresponding time slice (it is exists).
This function safely retrieves a
timeSliceContainer
. In the case of a valid time slice key, the corresponding object will be retrieved. However, in the case of “fullProcessing”, the object will beNone
so we can immediately return the full object. Errors will be appended under thetimeSliceKey
key.Note
For the error format in
error
, see the web app README.Parameters: - subsystem (subsystemContainer) – Subsystem for which the time slices request was made.
- error (dict) – Contains any possible errors following the defined error format. We will append any new errors to it.
Returns: - (timeSliceKey, timeSlice) where timeSliceKey (str) is the key under which the time slice
is stored or “fullProcessing” (which indicates full processing), and timeSlice (timeSliceContainer) is the corresponding time slice retrieved from the subsystem, or None if for any reason it could not be retrieved.
Return type: tuple
-
overwatch.webApp.validation.
validateHistGroupAndHistName
(histGroup, histName, subsystem, run, error)[source]¶ Check that the given hist group or hist name exists in the subsystem.
Look for the requested hist group or hist name within a given subsystem. It requires that the hist group and hist name have already been validated to ensure that they are valid strings or
None
. Note that it could be perfectly valid for both to beNone
!Note
As of Sept 2016, this check is not performed on the run page because it seems unnecessary to check every single value and there could be a substantial performance cost. This should be revisited in the future if it becomes a problem.
Note
For the error format in
error
, see the web app README.Parameters: - histGroup (str or None) – Requested hist group.
- histName (str or None) – Requested hist name.
- subsystem (subsystemContainer) – Subsystem which should contain the hist group and hist name.
- run (runContainer) – Run for which the hist group and hist name should exist.
- error (dict) – Contains any possible errors following the defined error format. We will append any new errors to it.
Returns: - It will append an error to the error dict if there is a problem with the given hist
group or hist nine. The error dict should be checked by the returning function to determine the result and decide how to proceed.
Return type: None
-
overwatch.webApp.validation.
validateLoginPostRequest
(request)[source]¶ Validates the login POST request.
Note
The error format is different here. Instead of a list in a dict, we simply have a string.
Parameters: request (Flask.request) – The request object from Flask. - Return
- tuple: (errorValue, username, password), where errorValue (str) contains the error that
- may have occurred, username (str) is the username extracted from POST request, and password (str) is the password extracted from POST request.
-
overwatch.webApp.validation.
validateRunPage
(runDir, subsystemName, requestedFileType, runs)[source]¶ Validates requests to the various run page types (handling individual run pages and root files).
The return tuple contains the validated values. The error value should always be checked first before using the other return values (they will be safe, but may not be meaningful).
Note
For the error format in
error
, see the web app README.Note
The listed args (after the first four) are provided through the flask
request.args
dictionary.Parameters: - runDir (str) – String containing the run number. For an example run 123456, it should be
formatted as
Run123456
- subsystemName (str) – The current subsystem in the form of a three letter, all capital name (ex.
EMC
). - requestedFileType (str) – Either “runPage”, which corresponds to a standard run page or “rootFiles”, which corresponds to the page displaying the available root files.
- runs (BTree) – Dict-like object which stores all run, subsystem, and hist information. Keys are the
in the
runDir
format (“Run123456”), while the values arerunContainer
objects. This should be retrieved from the database. - jsRoot (bool) – True if the response should use jsRoot instead of images.
- ajaxRequest (bool) – True if the response should be via AJAX.
- requestedHistGroup (str) – Name of the requested hist group. It is fine for it to be an empty string.
- requestedHist (str) – Name of the requested histogram. It is fine for it to be an empty string.
Returns: - (error, run, subsystem, requestedFileType, jsRoot, ajaxRequest, requestedHistGroup, requestedHist, timeSliceKey, timeSlice)
where error (dict) contains any possible errors, run (runContainer) corresponds to the current run, subsystem (subsystemContainer) corresponds to the current subsystem, requestedFileType (str) is the type of run page (“runPage” or “rootFiles”), jsRoot (bool) is True if the response should use jsRoot, ajaxRequest (bool) is true if the response should be as AJAX, requestedHistGroup (str) is the name of the requested hist group, requestedHist (str) is the name of the requested histogram, timeSliceKey (str) is the time slice key, and timeSlice (timeSliceContainer) is the time slice object. For more on the last two arguments, see
retrieveAndValidateTimeSlice(...)
.
Return type: tuple
- runDir (str) – String containing the run number. For an example run 123456, it should be
formatted as
-
overwatch.webApp.validation.
validateTimeSlicePostRequest
(request, runs)[source]¶ Validates the time slice POST request.
The return tuple contains the validated values. The error value should always be checked first before using the other return values (they will be safe, but may not be meaningful).
Warning
If an error occurs in determining the run or subsystem, we cannot retrieve the rest of the information necessary to validate the request, so the rest of the values in the return tuple are set to
None
.Note
For the error format in
errorValue
, see the web app README.Note
The listed args (after the first two) are provided through the flask
request.form
dictionary.Parameters: - request (Flask.request) – The request object from Flask.
- runs (BTree) – Dict-like object which stores all run, subsystem, and hist information. Keys are the
in the
runDir
format (“Run123456”), while the values arerunContainer
objects. - minTime (float) – Minimum time for the time slice.
- maxTime (float) – Maximum time for the time slice.
- runDir (str) – String containing the run number. For an example run 123456, it should be
formatted as
Run123456
. - subsystemName (str) – The current subsystem in the form of a three letter, all capital name (ex.
EMC
). - scaleHists (str) – True if the hists should be scaled by the number of events. Converted from string to bool.
- hotChannelThreshold (int) – Value of the hot channel threshold.
- histGroup (str) – Name of the requested hist group. It is fine for it to be an empty string.
- histName (str) – Name of the requested histogram. It is fine for it to be an empty string.
Returns: - (errorValue, minTime, maxTime, runDir, subsystemName, scrollAmount) where errorValue (dict)
containers any possible errors, minTime (float) is the minimum time for the time slice, maxTime (float) is the maximum time for the time slice, runDir (str) is the run dir formatted string for which the time slice should be performed, subsystemName (str) is the current subsystem in the form of a three letter, all capital name (ex.
EMC
), and scrollAmount (float) is the amount to scroll down the page to return to precisely where the user was previously.
Return type: tuple
-
overwatch.webApp.validation.
validateTrending
(request)[source]¶ Validate requests to the trending page.
The return tuple contains the validated values. The error value should always be checked first before using the other return values (they will be safe, but may not be meaningful).
Note
For the error format in
error
, see the web app README.Note
Function args are provided through the flask
request.args
dictionary.Parameters: - request (Flask.request) – The request object from Flask.
- jsRoot (bool) – True if the response should use jsRoot instead of images.
- ajaxRequest (bool) – True if the response should be via AJAX.
- subsystemName (str) – Name of the requested subsystem. It is fine for it to be an empty string.
Provided via the
histGroup
field since it is treated identically, allowing us to avoid the need to define another field for this one case. - histName (str) – Name of the requested histogram. It is fine for it to be an empty string.
Returns: - (error, subsystemName, requestedHist, jsRoot, ajaxRequest), where where error (dict) contains
any possible errors, subsystemName (str) corresponds to the current subsystem, subsystemName (str) is the requested subsystem in the form of a three letter, all capital name (ex.
EMC
). jsRoot (bool) is True if the response should use jsRoot, ajaxRequest (bool) is true if the response should be as AJAX.
Return type: tuple
overwatch.webApp.webApp module¶
Web App for serving Overwatch results, as well as access to user defined reprocessing and times slices.
This is the main web app executable, so it contains quite some functionality, especially that which is not so obvious how to refactor when using flask. Routing is divided up into authenticated and unauthenticated views.
-
overwatch.webApp.webApp.
contact
()[source]¶ Simple contact page so we can provide general information and support to users.
Also exposes useful links for development (for test data), and system status information to administrators (which must authenticate as such).
Note
Function args are provided through the flask request object.
Parameters: ajaxRequest (bool) – True if the response should be via AJAX. Returns: Contact page populated via template. Return type: Response
-
overwatch.webApp.webApp.
handleCSRFError
(error)[source]¶ Handle CSRF error.
Takes advantage of the property of the
CSRFError
class which will return a string description when called withstr()
.Note
The only requests that could fail due to a CSRF token issue are those made with AJAX, so it is reasonable to return an AJAX formatted response.
Note
For the error format in
errors
, see the web app README.Parameters: error (CSRFError) – Error object raised during as CSRF validation failure. Returns: json
encoded response containing the error.Return type: str
-
overwatch.webApp.webApp.
index
(*args, **kwargs)[source]¶ This is run list, which is the main page for logged in users.
The run list shows all available runs, which links to available subsystem histograms, as well as the underlying root files. The current status of data taking, as extracted from when the last file was received, is displayed in the drawer, as well as some links down the page to allow runs to be moved through quickly. The main content is paginated in a fairly rudimentary manner (it should be sufficient for our purposes). We have selected to show 50 runs per page, which seems to be a reasonable balance between showing too much or too little information. This can be tuned further if necessary.
Note
Function args are provided through the flask request object.
Parameters: - ajaxRequest (bool) – True if the response should be via AJAX.
- runOffset (int) – Number of runs to offset into the run list. Default: 0.
Returns: The main index page populated via template.
Return type: Response
-
overwatch.webApp.webApp.
load_user
(user)[source]¶ Used to retrieve a remembered user so that they don’t need to login again each time they visit the site.
Parameters: user (str) – Username to retrieve. Returns: - The user stored in the database which corresponds to the given username, or
None
if it doesn’t exist.
Return type: auth.User
-
overwatch.webApp.webApp.
login
()[source]¶ Login function. This is is the first page the user sees.
Unauthenticated users are also redirected here if they try to access something restricted. After logging in, it should then forward them to resource they requested.
Note
Function args are provided through the flask request object.
Parameters: - ajaxRequest (bool) – True if the response should be via AJAX.
- previousUsername (str) – The username that was previously used to login. Used to check when automatic login should be performed (if it’s enabled).
Returns: - Response based on the provided request. Possible responses included validating
and logging in the user, rejecting invalid user credentials, or redirecting unauthenticated users from a page which requires authentication (it will redirect back after login).
Return type: response
-
overwatch.webApp.webApp.
logout
(*args, **kwargs)[source]¶ Logs out an authenticated user.
Once completed, it will always redirect to back to
login()
. If the user then logs in, they will be redirected back to index. Some care is required to handle all of the edge cases - these are handled via careful redirection inlogin()
and therouting
module.Warning
Careful in making changes to the routing related to function, as it is hard coded in
`routing.redirectBack()
!Note
previousUsername
is provided to the next request so we can do the right thing on automatic login. In that case, we want to provide automatic login, but also allow the opportunity to logout and then explicitly login with different credentials.Parameters: None – Returns: Redirect back to the login page. Return type: Response
-
overwatch.webApp.webApp.
overwatchStatus
(*args, **kwargs)[source]¶ Query and determine the status of some parts of Overwatch.
This function takes advantage of the status functionality of the web app to determine the state of any deployed web apps that are specified in the web app config. This is achieved by sending requests to all other sites and then aggregating the results. Each request is allowed a 0.5 second timeout.
It will also provide information on when the last files were received from other sites.
This functionality will only work if the web app is accessible from the site where this is run. This may not always be the case.
Note
Since the GET requests are blocking, it can appear that the web app is hanging. However, this is just due to the time that the requests take.
Warning
This can behave somewhat strangely using the flask development server, especially if there is reloading. If possible, it is best to run with
uwsgi
for testing of this function.Note
Function args are provided through the flask request object.
Parameters: ajaxRequest (bool) – True if the response should be via AJAX. Returns: Status template populated with the status of Overwatch sites specified in the configuration. Return type: Response
-
overwatch.webApp.webApp.
protected
(*args, **kwargs)[source]¶ Serves the underlying files.
This function is response for actually making files available. Ideally, these would be served via the production web server, but since access to the data requires authentication, we instead have to provide access via this function. To provide this function, we utilized the approach described here.
Note
This function ignores GET parameters. This is done intentionally to allow for avoiding problematic caching by a browser. To avoid this caching, simply pass an additional get parameter after the filename which varies when we need to avoid the cache. This is particularly useful for time slices, where the name could be the same, but the information has changed since last being served.
Parameters: filename (str) – Path to the file to be served. Returns: File with the proper headers. Return type: Response
-
overwatch.webApp.webApp.
runPage
(*args, **kwargs)[source]¶ Serves the run pages and root files for a request run.
This is really the main function for serving information in Overwatch. The run page provides subsystem specific histograms and information to the user. Time slices and user directed reprocessing is also made available through this page. If a subsystem has made a customized run page, this will automatically be served. If they haven’t, then a default page will be provided.
This function serves both run pages, which display histograms, as well as root files pages, which provide direct access to the underlying root files. Since they require similar information, it is convenient to provide access to both of them from one function.
Note
Some function args (after the first 3) are provided through the flask request object.
Warning
Careful if changing the routing for this function, as the display swtich for the time slices button in the web app depends on “runPage” being in this route. If this is changed, then the
js
also needs to be changed.Parameters: - runNumber (int) – Run number of interest.
- subsystemName (str) – Name of the subsystem of interest.
- requestedFileType (str) – Type of file in which we are interested. Can be either
runPage
(corresponding to a run page) orrootFiles
(corresponding to access to the underlying root files). - jsRoot (bool) – True if the response should use jsRoot instead of images.
- ajaxRequest (bool) – True if the response should be via AJAX.
- requestedHistGroup (str) – Name of the requested hist group. It is fine for it to be an empty string.
- requestedHist (str) – Name of the requested histogram. It is fine for it to be an empty string.
Returns: A run page or root files page populated via template.
Return type: Response
-
overwatch.webApp.webApp.
statusQuery
()[source]¶ Returns the status of the Overwatch server instance.
This can be accessed by a GET request. If the request is successful, it will response with “Alive” and the response code 200. If it didn’t work properly, then the response won’t come through properly, indicating that an action must be taken to restart the web app.
Note
It doesn’t require authentication to simply the process of querying it. This should be fine because the information that the web app is up isn’t sensitive.
Parameters: None – Returns: - Contains a string, “Alive”, and a 200 response code to indicate that the web app is still up.
- If the database is somehow not available, it will return “DB failed” and a 500 response code. A response timeout indicates that the web app is somehow down.
Return type: Response
-
overwatch.webApp.webApp.
testingDataArchive
(*args, **kwargs)[source]¶ Provides a zip archive of test data for Overwatch development.
This function will look through at most the 5 most recent runs, looking for the minimum number of files necessary for running Overwatch successfully. These files will be zipped up and provided to the user. The minimum files are the combined file, and the most recent file received for the subsystem (they are usually the same, but it is easier to include both). If possible, an additional file is included for testing the time slice and trending functionality. It may not always be available if runs are extremely short. The zip archive will include all subsystems which are available. It will skip runs where any subsystem is unavailable to ensure that the data provided is of more utility.
Warning
Careful in changing the routing for this function, as the name of it is hard coded in
webApp.routing.redirectBack()
. This hard coding is to avoid a loop where the user is stuck accessing this file after logging in.Parameters: None – Returns: Redirect to the newly created file. Return type: redirect
-
overwatch.webApp.webApp.
timeSlice
(*args, **kwargs)[source]¶ Handles time slice and user reprocessing requests.
This is the main function for serving user requests. This function calls out directly to the processing module to perform the actual time slice or reprocessing request. It provides access to this functionality through the interface built into the header of the run page. In the case of a POST request, it handles, validates, and processes the timing request, rendering the result template and returning the user to the same spot as in the previous page. A GET request is invalid and will return an error (but the route itself is allowed to check that it is handled correctly).
This request should always be submitted via AJAX.
Note
Function args are provided through the flask request object.
Parameters: - jsRoot (bool) – True if the response should use jsRoot instead of images.
- minTime (float) – Minimum time for the time slice.
- maxTime (float) – Maximum time for the time slice.
- runDir (str) – String containing the run number. For an example run 123456, it should be
formatted as
Run123456
. - subsystemName (str) – The current subsystem in the form of a three letter, all capital name (ex.
EMC
). - scaleHists (str) – True if the hists should be scaled by the number of events. Converted from string to bool.
- hotChannelThreshold (int) – Value of the hot channel threshold.
- histGroup (str) – Name of the requested hist group. It is fine for it to be an empty string.
- histName (str) – Name of the requested histogram. It is fine for it to be an empty string.
Returns: - A run page template populated with information from a newly processed time slice (via a redirect
to
runPage()
). In case of error(s), returns the error message(s).
Return type: Response
-
overwatch.webApp.webApp.
upgradeDocker
(*args, **kwargs)[source]¶ Kill
supervisord
in the docker image so the docker image will stop.On the ALICE offline infrastructure, a stopped docker image will cause the image to be upgraded and restarted. Thus, we can intentionally stop the image indirectly by killing the supervisor process to force an upgrade.
Note
This operation requires administrative rights (as the
emcalAdmin
user).Warning
This is untested and is unsupported in any other infrastructure! It is experimental as of August 2018.
Note
Function args are provided through the flask request object.
Parameters: ajaxRequest (bool) – True if the response should be via AJAX. Returns: - Likely a timeout if the function was successful, or a response with an error message
- if the function was unsuccessful.
Return type: Response or None