api: handle submit of forms with date, file and map fields (#10059)

This commit is contained in:
Benjamin Dauvergne 2016-02-23 15:17:23 +01:00 committed by Frédéric Péters
parent 9f9599afee
commit efd1af0770
4 changed files with 109 additions and 13 deletions

View File

@ -44,6 +44,38 @@ différentes pages définies dans le formulaire (mode flux).
nom de variable) et les valeurs le contenu de ces champs.
</p>
<list>
<item>
<p>
Les champs de type simple tels que « Texte », « Texte long » ou
« Courriel » sont des chaînes de caractères.
</p>
</item>
<item>
<p>
Les champs de type « Date » sont des chaînes de caractères au format
ISO-8601, i.e. <code>YYYY-MM-DD</code>.
</p>
</item>
<item>
<p>
Les champs de type « Fichier » sont des dictionnaires contenant les clés
<code>filename</code> pour le nom de fichier et <code>content</code> pour le
contenu de celui-ci, encodé en base64.
</p>
</item>
<item>
<p>
Les champs de type « Carte » sont des dictionnaires contenant les clés
<code>lat</code> pour la latitute en nombre décimal et <code>lon</code>
pour la longitude en nombre décimal.
</p>
</item>
</list>
<p>
L'attribut <code>meta</code> est optionnel et contient une série de
paramètres supplémentaires concernant le formulaire.

View File

@ -439,6 +439,9 @@ def test_formdef_submit_with_varname(pub, local_user):
data_source={'type': 'foobar'}),
fields.ItemField(id='2', label='foobar2', varname='foobar2',
data_source={'type': 'foobar_jsonp'}),
fields.DateField(id='3', label='foobar3', varname='date'),
fields.FileField(id='4', label='foobar4', varname='file'),
fields.MapField(id='5', label='foobar5', varname='map'),
]
formdef.store()
data_class = formdef.data_class()
@ -450,19 +453,30 @@ def test_formdef_submit_with_varname(pub, local_user):
signed_url = sign_url('http://example.net/api/formdefs/test/submit' +
'?format=json&orig=coucou&email=%s' % urllib.quote(local_user.email), '1234')
url = signed_url[len('http://example.net'):]
resp = get_app(pub).post_json(url,
{'data':
{'foobar0': 'xxx',
'foobar1': '1',
'foobar1_structured': {
'id': '1',
'text': 'foo',
'more': 'XXX',
},
'foobar2': 'bar',
'foobar2_raw': '10',
}
})
payload = {
'data':
{
'foobar0': 'xxx',
'foobar1': '1',
'foobar1_structured': {
'id': '1',
'text': 'foo',
'more': 'XXX',
},
'foobar2': 'bar',
'foobar2_raw': '10',
'date': '1970-01-01',
'file': {
'filename': 'test.txt',
'content': base64.b64encode('test'),
},
'map': {
'lat': 1.5,
'lon': 2.25,
},
}
}
resp = get_app(pub).post_json(url, payload)
assert resp.json['err'] == 0
assert data_class.get(resp.json['data']['id']).status == 'wf-new'
assert data_class.get(resp.json['data']['id']).user_id == str(local_user.id)
@ -472,6 +486,20 @@ def test_formdef_submit_with_varname(pub, local_user):
assert data_class.get(resp.json['data']['id']).data['1_structured'] == source[0]
assert data_class.get(resp.json['data']['id']).data['2'] == '10'
assert data_class.get(resp.json['data']['id']).data['2_display'] == 'bar'
assert data_class.get(resp.json['data']['id']).data['3'] == time.struct_time(
(1970, 1, 1, 0, 0, 0, 3, 1, -1))
assert data_class.get(resp.json['data']['id']).data['4'].orig_filename == 'test.txt'
assert data_class.get(resp.json['data']['id']).data['4'].get_content() == 'test'
assert data_class.get(resp.json['data']['id']).data['5'] == '1.5;2.25'
# test bijectivity
assert (formdef.fields[3].get_json_value(data_class.get(resp.json['data']['id']).data['3']) ==
payload['data']['date'])
for k in payload['data']['file']:
data = data_class.get(resp.json['data']['id']).data['4']
assert formdef.fields[4].get_json_value(data)[k] == payload['data']['file'][k]
assert (formdef.fields[5].get_json_value(data_class.get(resp.json['data']['id']).data['5']) ==
payload['data']['map'])
data_class.wipe()
@ -492,6 +520,7 @@ def test_categories(pub):
formdef.fields = []
formdef.keywords = 'mobile, test'
formdef.store()
formdef.data_class().wipe()
formdef = FormDef()
formdef.name = 'test 2'
@ -499,6 +528,7 @@ def test_categories(pub):
formdef.fields = []
formdef.keywords = 'foobar'
formdef.store()
formdef.data_class().wipe()
resp = get_app(pub).get('/api/categories/')
resp2 = get_app(pub).get('/categories', headers={'Accept': 'application/json'})
@ -517,6 +547,7 @@ def test_categories_formdefs(pub):
formdef2.category_id = None
formdef2.fields = []
formdef2.store()
formdef2.data_class().wipe()
resp = get_app(pub).get('/api/categories/category/formdefs/')
resp2 = get_app(pub).get('/category/json')

View File

@ -243,6 +243,13 @@ class ApiFormdefDirectory(Directory):
data[field.id] = data.pop(field.varname)
if field.store_structured_value and structured in data:
data['%s_structured' % field.id] = data.pop(structured)
# parse special fields
for field in self.formdef.fields:
if not hasattr(field, 'from_json_value'):
continue
if not field.id in data:
continue
data[field.id] = field.from_json_value(data[field.id])
formdata.data = data
meta = json_input.get('meta') or {}
if meta.get('backoffice-submission'):

View File

@ -763,6 +763,19 @@ class FileField(WidgetField):
'content': base64.b64encode(value.get_content())
}
def from_json_value(self, value):
if 'filename' in value and 'content' in value:
content = base64.b64decode(value['content'])
content_type = value.get('content_type', 'application/octet-stream')
if content_type.startswith('text/'):
charset = 'utf-8'
else:
charset = None
upload = PicklableUpload(value['filename'], content_type, charset)
upload.receive([content])
return upload
return None
def perform_more_widget_changes(self, form, kwargs, edit = True):
if not edit:
value = get_request().get_field(self.field_key)
@ -915,6 +928,13 @@ class DateField(WidgetField):
except TypeError:
return ''
def from_json_value(self, value):
try:
return time.strptime(value, '%Y-%m-%d')
except (TypeError, ValueError):
return None
register_field_class(DateField)
@ -1756,6 +1776,12 @@ class MapField(WidgetField):
return None
return {'lat': lat, 'lon': lon}
def from_json_value(self, value):
if 'lat' in value and 'lon' in value:
return '%s;%s' % (float(value['lat']), float(value['lon']))
else:
return None
register_field_class(MapField)