From 2dc2c7aca837d2713dac6a057681dc62a6f18f9b Mon Sep 17 00:00:00 2001
From: Emmanuel Cazenave <ecazenave@entrouvert.com>
Date: Fri, 22 Nov 2019 12:16:19 +0100
Subject: [PATCH] templatetags: pass unicode to html_format (#37880)

---
 passerelle/base/templatetags/passerelle.py | 40 +++++++++++-----------
 tests/test_templatetags.py                 | 20 ++++++++++-
 2 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/passerelle/base/templatetags/passerelle.py b/passerelle/base/templatetags/passerelle.py
index 465e3b03..fe3da0fa 100644
--- a/passerelle/base/templatetags/passerelle.py
+++ b/passerelle/base/templatetags/passerelle.py
@@ -114,15 +114,15 @@ def render_json_schema(schema):
             return mark_safe('<em>%s</em>') % _('always valid')
         if schema is False:
             return mark_safe('<em>%s</em>') % _('always invalid')
-        return format_html('<tt>{!r}</tt>', schema)
+        return format_html(u'<tt>{!r}</tt>', schema)
 
     def many_of(name, schemas):
-        s = format_html('<b>{}</b>', name)
+        s = format_html(u'<b>{}</b>', name)
         parts = [render_json_schema(schema) for schema in schemas]
         if any('\n' in part for part in parts):
             s += '<ul>'
             for part in parts:
-                s += format_html('<li>{0}</li>\n', part)
+                s += format_html(u'<li>{0}</li>\n', part)
             s += '</ul>'
         else:
             s += ' [ ' + ' | '.join(parts) + ' ]'
@@ -153,17 +153,17 @@ def render_json_schema(schema):
         pattern = schema.pop('pattern', '')
         if enum:
             enum = mark_safe(' | '.join(
-                [format_html('"<tt>{}</tt>"', el) for el in enum]))
+                [format_html(u'"<tt>{}</tt>"', el) for el in enum]))
         s = '<b>string'
         if max_length or min_length:
-            s += format_html('[{0}:{1}]', min_length, max_length)
+            s += format_html(u'[{0}:{1}]', min_length, max_length)
         s += '</b>'
         if enum:
             s += ' %s' % enum
         if pattern:
-            s += format_html(' /<tt>{}</tt>/', pattern)
+            s += format_html(u' /<tt>{}</tt>/', pattern)
         if schema:
-            s += format_html('\n{!r}', schema)
+            s += format_html(u'\n{!r}', schema)
         return mark_safe(s)
     if typ == 'integer':
         if not schema:
@@ -184,17 +184,17 @@ def render_json_schema(schema):
         required_keys = schema.pop('required', [])
         additional_properties = schema.pop('additionalProperties', True)
         if unflatten:
-            s += format_html(', <em class="unflatten">%s</em>', _('unflatten'))
+            s += format_html(u', <em class="unflatten">%s</em>', _('unflatten'))
         if merge_extra:
-            s += format_html(', <em class="merge-extra">%s</em>', _('merge extra'))
+            s += format_html(u', <em class="merge-extra">%s</em>', _('merge extra'))
         if not additional_properties:
-            s += format_html(', <em class="additional-properties-false">{}</em>', _('no additional properties'))
+            s += format_html(u', <em class="additional-properties-false">{}</em>', _('no additional properties'))
         if title:
-            s += format_html(', <em class="title">{}</em>', title)
+            s += format_html(u', <em class="title">{}</em>', title)
         if schema:
-            s += format_html('<tt class="raw">{!r}</tt>', schema)
+            s += format_html(u'<tt class="raw">{!r}</tt>', schema)
         if description:
-            s += format_html('\n<p class="description">{}</p>', description)
+            s += format_html(u'\n<p class="description">{}</p>', description)
         s += ' '
         if properties:
             s += '\n<ul>'
@@ -206,26 +206,26 @@ def render_json_schema(schema):
                 required = key in required_keys
                 sub_description = sub.pop('description', '')
                 sub_title = sub.pop('title', '')
-                s += format_html('<li><tt>{0}</tt>', key)
+                s += format_html(u'<li><tt>{0}</tt>', key)
                 if required:
-                    s += format_html('<span title="{}" class="required">*</span>', _('required'))
+                    s += format_html(u'<span title="{}" class="required">*</span>', _('required'))
                 if description or sub:
                     s += ' :'
                 if sub_title:
-                    s += format_html(' <em>{0}</em>', sub_title)
+                    s += format_html(u' <em>{0}</em>', sub_title)
                 elif sub_description and '\n' not in sub_description:
-                    s += format_html(' <em>{0}</em>', sub_description)
+                    s += format_html(u' <em>{0}</em>', sub_description)
                 if sub_title or '\n' in sub_description:
-                    s += format_html('\n<p class="description">{}</p>', sub_description)
+                    s += format_html(u'\n<p class="description">{}</p>', sub_description)
                 if sub:
-                    s += format_html('\n{0}', render_json_schema(sub))
+                    s += format_html(u'\n{0}', render_json_schema(sub))
                 s += '</li>'
             s += '</ul>'
         return mark_safe(s)
     if typ == 'boolean':
         if not schema:
             return mark_safe('<b>boolean</b>')
-    return format_html('<em>{0} {1!r}</em>', _('unknown validation'), original_schema)
+    return format_html(u'<em>{0} {1!r}</em>', _('unknown validation'), original_schema)
 
 
 @register.simple_tag(takes_context=False)
diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py
index 8d605bc3..5b1f66b1 100644
--- a/tests/test_templatetags.py
+++ b/tests/test_templatetags.py
@@ -17,8 +17,9 @@
 import inspect
 
 from django.apps import apps
+from django.utils import translation
 
-from passerelle.base.templatetags.passerelle import render_body_schemas
+from passerelle.base.templatetags.passerelle import render_body_schemas, render_json_schema
 
 
 def test_render_body_schemas(db):
@@ -41,3 +42,20 @@ def test_render_body_schemas(db):
     assert schemas , 'no endpoint with schema found'
     for schema, endpoint in schemas:
         assert render_body_schemas(schema), 'failed for %s' % endpoint
+
+
+def test_render_json_schema():
+    SCHEMA = {
+        '$schema': 'http://json-schema.org/draft-04/schema#',
+        'type': 'object',
+        'required': ['foo'],
+        'additionalProperties': False,
+        'properties': {
+            'foo': {
+                'type': 'string',
+            },
+        }
+    }
+    # Check that no unicode crash occurs
+    with translation.override('fr'):
+        render_json_schema(SCHEMA)
-- 
2.20.1

