wscall: add parameters to add elements to query string (#11207)

This commit is contained in:
Benjamin Dauvergne 2016-06-06 10:07:41 +02:00 committed by Frédéric Péters
parent 0f4809b388
commit fe688437e0
4 changed files with 83 additions and 9 deletions

View File

@ -28,6 +28,15 @@ par exemple transmettre une information particulière.
<code>https://www.example.net/notify?email=[session_user_email]</code>
</example>
<p>
Le tableau « Données à envoyer en paramètre » permet de décrire des données qui
seront transmises sous la forme de paramètres d'URL. 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
« = ». Les paramètres d'URL ne peuvent être que des chaînes, si ce n'est pas le
cas la donnée sera transformée en chaîne de force.
</p>
<p>
La case à cocher « Envoyer le formulaire (POST, en JSON) » indique que
l'ensemble des données du formulaire doivent être transmises, avec un appel de

View File

@ -308,6 +308,7 @@ def test_wscall_action():
wscall.post = False
wscall.request_signature_key = 'key'
wscall.post_data = {'one': '1', 'two': '=2', 'good:name': 'ok'}
wscall.qs_data = {'one': '2', 'two': '=3', 'good:name': 'ok'}
st1.items.append(wscall)
wscall.parent = st1
@ -318,6 +319,7 @@ def test_wscall_action():
assert wscall2.post == False
assert wscall2.request_signature_key == 'key'
assert wscall2.post_data == {'one': '1', 'two': '=2', 'good:name': 'ok'}
assert wscall2.qs_data == {'one': '2', 'two': '=3', 'good:name': 'ok'}
def test_backoffice_info_text():
wf = Workflow(name='info texts')

View File

@ -3,6 +3,7 @@ import pytest
import shutil
import time
import urllib2
import urlparse
import mock
@ -849,6 +850,28 @@ def test_webservice_call(pub):
rendered = formdata.evolution[-1].parts[-1].view()
assert 'Error during webservice call &quot;do that&quot;' in str(rendered)
item = WebserviceCallStatusItem()
item.method = 'GET'
item.post = False
item.url = 'http://remote.example.net?in_url=1'
item.qs_data = {
'str': 'abcd',
'one': '=1',
'evalme': '=form_number',
'error': '=1=3',
'in_url': '2',
}
pub.substitutions.feed(formdata)
item.perform(formdata)
assert http_requests.get_last('method') == 'GET'
qs = urlparse.parse_qs(http_requests.get_last('url').split('?')[1])
assert set(qs.keys()) == set(['in_url', 'str', 'one', 'evalme'])
assert qs['in_url'] == ['1', '2']
assert qs['one'] == ['1']
assert qs['evalme'] == [formdata.get_display_id()]
assert qs['str'] == ['abcd']
def test_timeout(pub):
workflow = Workflow(name='timeout')
st1 = workflow.add_status('Status1', 'st1')

View File

@ -22,6 +22,9 @@ import xml.etree.ElementTree as ET
import collections
import mimetypes
from StringIO import StringIO
import urllib
import urlparse
from quixote.html import TemplateIO, htmltext
from qommon.errors import ConnectionError
@ -103,6 +106,7 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
post = True
request_signature_key = None
post_data = None
qs_data = None
_method = None
response_type = 'json'
@ -135,7 +139,8 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
return ('url', 'post', 'varname', 'request_signature_key', 'post_data',
'action_on_4xx', 'action_on_5xx', 'action_on_bad_data',
'action_on_network_errors', 'notify_on_errors',
'record_errors', 'label', 'method', 'response_type')
'record_errors', 'label', 'method', 'response_type',
'qs_data')
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
if 'label' in parameters:
@ -150,6 +155,11 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
form.add(ComputedExpressionWidget, '%srequest_signature_key' % prefix,
title=_('Request Signature Key'),
value=self.request_signature_key)
if 'qs_data' in parameters:
form.add(WidgetDict, '%sqs_data' % prefix,
title=_('Query string data'),
value=self.qs_data or {},
element_value_type=ComputedExpressionWidget)
methods = collections.OrderedDict(
[('GET', _('GET')), ('POST', _('POST (JSON)'))])
if 'method' in parameters:
@ -234,6 +244,23 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
variables = get_publisher().substitutions.get_context_variables()
url = get_variadic_url(url, variables)
if self.qs_data: # merge qs_data into url
publisher = get_publisher()
parsed = urlparse.urlparse(url)
qs = list(urlparse.parse_qsl(parsed.query))
for key, value in self.qs_data.iteritems():
try:
value = self.compute(value, raises=True)
value = str(value)
except:
get_publisher().notify_of_exception(sys.exc_info())
else:
key = publisher.sitecharset2utf8(key)
value = publisher.sitecharset2utf8(value)
qs.append((key, value))
qs = urllib.urlencode(qs)
url = urlparse.urlunparse(parsed[:4] + (qs,) + parsed[5:6])
if self.request_signature_key:
signature_key = self.compute(self.request_signature_key)
if signature_key:
@ -372,11 +399,12 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
def get_jump_label(self):
return _('Error calling webservice')
def post_data_export_to_xml(self, xml_item, charset, include_id=False):
if not self.post_data:
def _kv_data_export_to_xml(self, xml_item, charset, include_id, attribute):
assert attribute
if not getattr(self, attribute):
return
el = ET.SubElement(xml_item, 'post_data')
for (key, value) in self.post_data.items():
el = ET.SubElement(xml_item, attribute)
for (key, value) in getattr(self, attribute).items():
item = ET.SubElement(el, 'item')
if type(key) is unicode:
ET.SubElement(item, 'name').text = key
@ -391,14 +419,26 @@ class WebserviceCallStatusItem(WorkflowStatusItem):
else:
raise AssertionError('unknown type for value (%r)' % key)
def post_data_init_with_xml(self, elem, charset, include_id=False):
def _kv_data_init_with_xml(self, elem, charset, include_id, attribute):
if elem is None:
return
self.post_data = {}
setattr(self, attribute, {})
for item in elem.findall('item'):
key = item.find('name').text.encode(charset)
value = item.find('value').text.encode(charset)
self.post_data[key] = value
getattr(self, attribute)[key] = value
def post_data_export_to_xml(self, xml_item, charset, include_id=False):
self._kv_data_export_to_xml(xml_item, charset, include_id=include_id,
attribute='post_data')
def post_data_init_with_xml(self, elem, charset, include_id=False):
self._kv_data_init_with_xml(elem, charset, include_id=include_id, attribute='post_data')
def qs_data_export_to_xml(self, xml_item, charset, include_id=False):
self._kv_data_export_to_xml(xml_item, charset, include_id=include_id, attribute='qs_data')
def qs_data_init_with_xml(self, elem, charset, include_id=False):
self._kv_data_init_with_xml(elem, charset, include_id=include_id, attribute='qs_data')
register_item_class(WebserviceCallStatusItem)