Mercurial > p > roundup > code
view test/tx_Source_detector.py @ 5710:0b79bfcb3312
Add support for making an idempotent POST. This allows retrying a POST
that was interrupted. It involves creating a post once only (poe) url
/rest/data/<class>/@poe/<random_token>. This url acts the same as a
post to /rest/data/<class>. However once the @poe url is used, it
can't be used for a second POST.
To make these changes:
1) Take the body of post_collection into a new post_collection_inner
function. Have post_collection call post_collection_inner.
2) Add a handler for POST to rest/data/class/@poe. This will return a
unique POE url. By default the url expires after 30 minutes. The
POE random token is only good for a specific user and is stored in
the session db.
3) Add a handler for POST to rest/data/<class>/@poe/<random token>.
The random token generated in 2 is validated for proper class (if
token is not generic) and proper user and must not have expired.
If everything is valid, call post_collection_inner to process the
input and generate the new entry.
To make recognition of 2 stable (so it's not confused with
rest/data/<:class_name>/<:item_id>), removed @ from
Routing::url_to_regex.
The current Routing.execute method stops on the first regular
expression to match the URL. Since item_id doesn't accept a POST, I
was getting 405 bad method sometimes. My guess is the order of the
regular expressions is not stable, so sometime I would get the right
regexp for /data/<class>/@poe and sometime I would get the one for
/data/<class>/<item_id>. By removing the @ from the url_to_regexp,
there was no way for the item_id case to match @poe.
There are alternate fixes we may need to look at. If a regexp matches
but the method does not, return to the regexp matching loop in
execute() looking for another match. Only once every possible match
has failed should the code return a 405 method failure.
Another fix is to implement a more sophisticated mechanism so that
@Routing.route("/data/<:class_name>/<:item_id>/<:attr_name>", 'PATCH')
has different regexps for matching <:class_name> <:item_id> and
<:attr_name>. Currently the regexp specified by url_to_regex is used
for every component.
Other fixes:
Made failure to find any props in props_from_args return an empty
dict rather than throwing an unhandled error.
Make __init__ for SimulateFieldStorageFromJson handle an empty json
doc. Useful for POSTing to rest/data/class/@poe with an empty
document.
Testing:
added testPostPOE to test/rest_common.py that I think covers
all the code that was added.
Documentation:
Add doc to rest.txt in the "Client API" section titled: Safely
Re-sending POST". Move existing section "Adding new rest endpoints" in
"Client API" to a new second level section called "Programming the
REST API". Also a minor change to the simple rest client moving the
header setting to continuation lines rather than showing one long
line.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sun, 14 Apr 2019 21:07:11 -0400 |
| parents | 64b05e24dbd8 |
| children | 9938c40e03bc |
line wrap: on
line source
# # Example output when the web interface changes item 3 and the email # (non pgp) interface changes item 4: # # tx_SourceCheckAudit(3) pre db.tx_Source: cgi # tx_SourceCheckAudit(4) pre db.tx_Source: email # tx_SourceCheckAudit(3) post db.tx_Source: cgi # tx_SourceCheckAudit(4) post db.tx_Source: email # tx_SourceCheckReact(4) pre db.tx_Source: email # tx_SourceCheckReact(4) post db.tx_Source: email # tx_SourceCheckReact(3) pre db.tx_Source: cgi # tx_SourceCheckReact(3) post db.tx_Source: cgi # # Note that the calls are interleaved, but the proper # tx_Source is associated with the same ticket. from __future__ import print_function import time as time def tx_SourceCheckAudit(db, cl, nodeid, newvalues): ''' An auditor to print the value of the source of the transaction that trigger this change. The sleep call is used to delay the transaction so that multiple changes will overlap. The expected output from this detector are 2 lines with the same value for tx_Source. Tx source is: None - Reported when using a script or it is an error if the change arrives by another method. "cli" - reported when using roundup-admin "web" - reported when using any web based technique "email" - reported when using an unautheticated email based technique "email-sig-openpgp" - reported when email with a valid pgp signature is used ''' if __debug__ and False: print("\n tx_SourceCheckAudit(%s) db.tx_Source: %s"%(nodeid, db.tx_Source)) newvalues['tx_Source'] = db.tx_Source # example use for real to prevent a change from happening if it's # submited via email # # if db.tx_Source == "email": # raise Reject, 'Change not allowed via email' def tx_SourceCheckReact(db, cl, nodeid, oldvalues): ''' An reactor to print the value of the source of the transaction that trigger this change. The sleep call is used to delay the transaction so that multiple changes will overlap. The expected output from this detector are 2 lines with the same value for tx_Source. Tx source is: None - Reported when using a script or it is an error if the change arrives by another method. "cli" - reported when using roundup-admin "web" - reported when using any web based technique "email" - reported when using an unautheticated email based technique "email-sig-openpgp" - reported when email with a valid pgp signature is used ''' if __debug__ and False: print(" tx_SourceCheckReact(%s) db.tx_Source: %s"%(nodeid, db.tx_Source)) def init(db): db.issue.audit('create', tx_SourceCheckAudit) db.issue.audit('set', tx_SourceCheckAudit) db.issue.react('set', tx_SourceCheckReact) db.issue.react('create', tx_SourceCheckReact) db.msg.audit('create', tx_SourceCheckAudit)
