wscall: allow extra data on POST (#6622)

This commit is contained in:
Thomas NOËL 2015-08-31 17:42:41 +02:00
parent d24711a7f0
commit fd9526cd80
4 changed files with 110 additions and 8 deletions

View File

@ -15,7 +15,7 @@
<p>
Cette action permet d'appeler un système tiers et d'éventuellement lui
transmettre les données du formulaire en cours.
transmettre des données, dont celles du formulaire en cours.
</p>
<p>
@ -36,6 +36,51 @@ format JSON, comme décrit dans cette <link xref="api-get#pull">page sur
l'API</link>.
</p>
<p>
Le tableau « Données à envoyer en POST » permet de décrire des données qui
seront transmises sous la forme d'un dictionnaire clé-valeur au format JSON.
Sur chaque ligne, la colonne de gauche est le nom de la clé, celle de droite la
valeur. La valeur peut être une expression Python, pour cela elle doit
commencer par le signe « = ».
</p>
<example>
<p>Ce tableau de valeurs :</p>
<table>
<tr>
<td><p><code>code_appel</code></p></td>
<td><p><code>w.c.s.</code></p></td>
</tr>
<tr>
<td><p><code>form_number</code></p></td>
<td><p><code>=form_number</code></p></td>
</tr>
</table>
<p>formera ce JSON :</p>
<code>
{
"code_appel": "w.c.s.",
"form_number": "4"
}
</code>
</example>
<note>
<list>
<item><p>
Si la case « Envoyer le formulaire (POST, en JSON) » est cochée et que des
« Données à envoyer en POST » sont indiquées, alors ces dernières sont ajoutées
dans le JSON du formulaire, dans une clé « extra ».
</p></item>
<item><p>
Si aucune donnée n'est indiquée et que le formulaire ne doit pas être transmis,
alors la requête HTTP effectuée est un GET sur l'URL.
</p></item>
</list>
</note>
<p>
Le paramètre « Nom de variable » permet d'enregistrer le résultat retourné
par le webservice, le retour HTTP de celui-ci sera enregistré dans

View File

@ -400,6 +400,9 @@ def test_webservice_call(pub):
item.perform(formdata)
assert http_requests.get_last('url') == 'http://remote.example.net'
assert http_requests.get_last('method') == 'POST'
payload = json.loads(http_requests.get_last('body'))
assert payload['url'].startswith('http://example.net/baz-')
assert int(payload['display_id']) == 1
item = WebserviceCallStatusItem()
item.url = 'http://remote.example.net'
@ -408,6 +411,31 @@ def test_webservice_call(pub):
assert http_requests.get_last('url') == 'http://remote.example.net'
assert http_requests.get_last('method') == 'GET'
item = WebserviceCallStatusItem()
item.url = 'http://remote.example.net'
item.post = False
item.post_data = {'str': 'abcd', 'one': '=1',
'evalme': '=form_number', 'error':'=1=3'}
pub.substitutions.feed(formdata)
item.perform(formdata)
assert http_requests.get_last('url') == 'http://remote.example.net'
assert http_requests.get_last('method') == 'POST'
payload = json.loads(http_requests.get_last('body'))
assert payload == {'one': 1, 'str': 'abcd', 'evalme': formdata.id}
item = WebserviceCallStatusItem()
item.url = 'http://remote.example.net'
item.post_data = {'str': 'abcd', 'one': '=1',
'evalme': '=form_number', 'error':'=1=3'}
pub.substitutions.feed(formdata)
item.perform(formdata)
assert http_requests.get_last('url') == 'http://remote.example.net'
assert http_requests.get_last('method') == 'POST'
payload = json.loads(http_requests.get_last('body'))
assert payload['extra'] == {'one': 1, 'str': 'abcd', 'evalme': formdata.id}
assert payload['url'].startswith('http://example.net/baz-')
assert int(payload['display_id']) == 1
item = WebserviceCallStatusItem()
item.url = 'http://remote.example.net'
item.post = False

View File

@ -15,9 +15,10 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import json
import sys
from qommon.form import *
from qommon.misc import http_get_page, http_post_request, get_variadic_url
from qommon.misc import http_get_page, http_post_request, get_variadic_url, JSONEncoder
from wcs.workflows import WorkflowStatusItem, register_item_class, template_on_formdata
from wcs.api import sign_url
@ -32,9 +33,10 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
varname = None
post = True
request_signature_key = None
post_data = None
def get_parameters(self):
return ('url', 'post', 'varname', 'request_signature_key')
return ('url', 'post', 'varname', 'request_signature_key', 'post_data')
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
if 'url' in parameters:
@ -45,10 +47,14 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
form.add(CheckboxWidget, '%spost' % prefix,
title=_('Post formdata (JSON)'),
value=self.post)
if 'post_data' in parameters:
form.add(WidgetDict, '%spost_data' % prefix,
title=_('Post data'),
value=self.post_data or {})
if 'varname' in parameters:
form.add(VarnameWidget, '%svarname' % prefix,
title=_('Variable Name'), value=self.varname)
if 'request_signature_key':
if 'request_signature_key' in parameters:
form.add(StringWidget, '%srequest_signature_key' % prefix,
title=_('Request Signature Key'),
value=self.request_signature_key)
@ -69,13 +75,34 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
headers = {'Content-type': 'application/json',
'Accept': 'application/json'}
post_data = None # payload
# if self.post_data exists, post_data is a dict built from it
if self.post_data:
post_data = {}
for (key, value) in self.post_data.items():
try:
post_data[key] = self.compute(value, raises=True)
except:
get_publisher().notify_of_exception(sys.exc_info())
# if formdata has to be sent, it's the payload. If post_data exists,
# it's added in formdata['extra']
if self.post:
formdata_as_json = formdata.export_to_json()
response, status, data, auth_header = http_post_request(
url, formdata_as_json, headers=headers, timeout=TIMEOUT)
formdata_dict = formdata.get_json_export_dict()
if post_data is not None:
formdata_dict['extra'] = post_data
post_data = formdata_dict
if post_data is not None:
post_data = json.dumps(post_data, cls=JSONEncoder,
encoding=get_publisher().site_charset)
response, status, data, authheader = http_post_request(
url, post_data, headers=headers, timeout=TIMEOUT)
else:
response, status, data, auth_header = http_get_page(
url, headers=headers, timeout=TIMEOUT)
if self.varname:
workflow_data = {'%s_status' % self.varname: status}
if status == 200:

View File

@ -836,7 +836,7 @@ class WorkflowStatusItem(object):
value = getattr(self, '%s_parse' % f)(value)
setattr(self, f, value)
def compute(self, var):
def compute(self, var, raises=False):
if not isinstance(var, basestring):
return var
if not var.startswith('='):
@ -845,6 +845,8 @@ class WorkflowStatusItem(object):
try:
return eval(var[1:], get_publisher().get_global_eval_dict(), vars)
except:
if raises:
raise
return var
def get_substitution_variables(self, formdata):