sql: use force_str() on filtered options (#38624)

This commit is contained in:
Frédéric Péters 2019-12-18 14:42:06 +01:00
parent 2d96602aeb
commit 81457aca77
3 changed files with 35 additions and 31 deletions

View File

@ -699,14 +699,14 @@ def test_backoffice_item_filter(pub):
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields.append(fields.ItemField(id='4', label='4th field', type='item',
items=['a', 'b', 'c', 'd'],
items=['â', 'b', 'c', 'd'],
display_locations=['validation', 'summary', 'listings']))
formdef.store()
for i, formdata in enumerate(formdef.data_class().select()):
if i%4 == 0:
formdata.data['4'] = 'a'
formdata.data['4_display'] = 'a'
formdata.data['4'] = 'â'
formdata.data['4_display'] = 'â'
elif i%4 == 1:
formdata.data['4'] = 'b'
formdata.data['4_display'] = 'b'
@ -722,25 +722,25 @@ def test_backoffice_item_filter(pub):
assert resp.form['filter-4-value'].value == ''
resp.form['filter-4-value'].value = 'a'
resp.form['filter-4-value'].value = 'â'
resp = resp.form.submit()
assert resp.text.count('<td>a</td>') > 0
assert resp.text.count('<td>b</td>') == 0
assert resp.text.count('<td>d</td>') == 0
assert resp.text.count(u'<td>â</td>') > 0
assert resp.text.count(u'<td>b</td>') == 0
assert resp.text.count(u'<td>d</td>') == 0
resp.form['filter-4-value'].value = 'b'
resp = resp.form.submit()
assert resp.text.count('<td>a</td>') == 0
assert resp.text.count('<td>b</td>') > 0
assert resp.text.count('<td>d</td>') == 0
assert resp.text.count(u'<td>â</td>') == 0
assert resp.text.count(u'<td>b</td>') > 0
assert resp.text.count(u'<td>d</td>') == 0
if not pub.is_using_postgresql():
# in pickle all options are always displayed
resp.form['filter-4-value'].value = 'c'
resp = resp.form.submit()
assert resp.text.count('<td>a</td>') == 0
assert resp.text.count('<td>b</td>') == 0
assert resp.text.count('<td>c</td>') == 0
assert resp.text.count(u'<td>â</td>') == 0
assert resp.text.count(u'<td>b</td>') == 0
assert resp.text.count(u'<td>c</td>') == 0
else:
# in postgresql, option 'c' is never used so not even listed
@ -749,7 +749,7 @@ def test_backoffice_item_filter(pub):
# check json view used to fill select filters from javascript
resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=4&' + resp.request.query_string)
assert [x['id'] for x in resp2.json['data']] == ['a', 'b', 'd']
assert [x['id'] for x in resp2.json['data']] == [u'â', u'b', u'd']
resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=4&_search=d&' + resp.request.query_string)
assert [x['id'] for x in resp2.json['data']] == ['d']
resp2 = app.get(resp.request.path + 'filter-options?filter_field_id=7&' + resp.request.query_string, status=404)
@ -761,7 +761,7 @@ def test_backoffice_item_filter(pub):
if status == 'accepted':
assert [x['id'] for x in resp2.json['data']] == []
else:
assert [x['id'] for x in resp2.json['data']] == ['a', 'b', 'd']
assert [x['id'] for x in resp2.json['data']] == [u'â', u'b', u'd']
def test_backoffice_item_double_filter(pub):
if not pub.is_using_postgresql():
@ -837,20 +837,20 @@ def test_backoffice_items_filter(pub):
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields.append(fields.ItemsField(id='4', label='4th field', type='items',
items=['a', 'b', 'c', 'd'],
items=['â', 'b', 'c', 'd'],
display_locations=['validation', 'summary', 'listings']))
formdef.store()
for i, formdata in enumerate(formdef.data_class().select()):
if i%4 == 0:
formdata.data['4'] = ['a', 'b']
formdata.data['4_display'] = 'a, b'
formdata.data['4'] = ['â', 'b']
formdata.data['4_display'] = 'â, b'
elif i%4 == 1:
formdata.data['4'] = ['b', 'd']
formdata.data['4_display'] = 'b, d'
elif i%4 == 2:
formdata.data['4'] = ['a']
formdata.data['4_display'] = 'a'
formdata.data['4'] = ['â']
formdata.data['4_display'] = 'â'
formdata.store()
app = login(get_app(pub))
@ -860,17 +860,17 @@ def test_backoffice_items_filter(pub):
assert resp.form['filter-4-value'].value == ''
resp.form['filter-4-value'].value = 'a'
resp.form['filter-4-value'].value = 'â'
resp = resp.form.submit()
assert resp.text.count('<td>a, b</td>') > 0
assert resp.text.count('<td>a</td>') > 0
assert resp.text.count('<td>b, d</td>') == 0
assert resp.text.count(u'<td>â, b</td>') > 0
assert resp.text.count(u'<td>â</td>') > 0
assert resp.text.count(u'<td>b, d</td>') == 0
resp.form['filter-4-value'].value = 'b'
resp = resp.form.submit()
assert resp.text.count('<td>a, b</td>') > 0
assert resp.text.count('<td>a</td>') == 0
assert resp.text.count('<td>b, d</td>') > 0
assert resp.text.count(u'<td>â, b</td>') > 0
assert resp.text.count(u'<td>â</td>') == 0
assert resp.text.count(u'<td>b, d</td>') > 0
if pub.is_using_postgresql():
# option 'c' is never used so not even listed
@ -879,9 +879,9 @@ def test_backoffice_items_filter(pub):
else:
resp.form['filter-4-value'].value = 'c'
resp = resp.form.submit()
assert resp.text.count('<td>a, b</td>') == 0
assert resp.text.count('<td>a</td>') == 0
assert resp.text.count('<td>b, d</td>') == 0
assert resp.text.count(u'<td>â, b</td>') == 0
assert resp.text.count(u'<td>â</td>') == 0
assert resp.text.count(u'<td>b, d</td>') == 0
assert resp.text.count('data-link') == 0 # no rows
def test_backoffice_csv(pub):

View File

@ -1083,6 +1083,8 @@ class FormPage(Directory):
exploded_options[option_key] = option_label
options = list(sorted(exploded_options.items(), key=lambda x: x[1]))
options = [(force_str(x), force_str(y)) for x, y in options]
return options
def filter_options(self):
@ -1103,7 +1105,8 @@ class FormPage(Directory):
options = [x for x in options if term.lower() in x[1].lower()]
options = options[:15]
get_response().set_content_type('application/json')
return json.dumps({'err': 0, 'data': [{'id': x[0], 'text': x[1]} for x in options]})
return json.dumps({'err': 0, 'data': [{'id': x[0], 'text': x[1]} for x in options]},
cls=misc.JSONEncoder)
def get_filter_sidebar(self, selected_filter=None, mode='listing', query=None, criterias=None):
r = TemplateIO(html=True)

View File

@ -1145,6 +1145,7 @@ class SqlMixin(object):
@classmethod
@guard_postgres
def select_distinct(cls, columns, clause=None):
# do note this method returns unicode strings.
conn, cur = get_connection_and_cursor()
sql_statement = 'SELECT DISTINCT ON (%s) %s FROM %s' % (columns[0], ', '.join(columns), cls._table_name)
where_clauses, parameters, func_clause = parse_clause(clause)