Ajoute 4 mécanismes moteur manquants pour le thème sécurité incendie : étiquette, carte, image SVG inline, bouton avec pièce jointe
Contenu et mécanisme uniquement, aucun style ajouté (voir consigne du 24/09/2026) : deux nouveaux kinds de contenu (badge/carte, rendu en div brutes sans CSS), un mode SVG inline pour l'image (svg_markup, nettoyé par un nouveau sanitizer allow-list avant chaque rendu) et un fichier téléchargeable joignable à un bouton (upload/download routes, stockage sous db.support_dir). Le futur système de templates portera l'habillage visuel de ces éléments. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e7c6ed7159
commit
a34bcf4159
@@ -225,3 +225,125 @@ def test_liste_puces_with_no_items_renders_an_empty_list(tmp_support_slug_cleanu
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert html == f'<ul class="docList" data-element-id="{element_id}" data-kind="liste_puces"></ul>'
|
||||
|
||||
|
||||
def test_badge_default_attributes_and_render(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "badge", page_id=page_id)
|
||||
element = doc_engine.get_document_element(slug, element_id)
|
||||
assert element is not None
|
||||
assert element["attributes"] == {"content": "Étiquette"}
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert html == f'<div class="docBadge" data-element-id="{element_id}" data-kind="badge">Étiquette</div>'
|
||||
|
||||
|
||||
def test_badge_escapes_content(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "badge", page_id=page_id)
|
||||
doc_engine.update_document_element_attributes(slug, element_id, {"content": "<script>alert(1)</script>"})
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "<script>" not in html
|
||||
assert "<script>" in html
|
||||
|
||||
|
||||
def test_carte_default_attributes_and_render(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "carte", page_id=page_id)
|
||||
element = doc_engine.get_document_element(slug, element_id)
|
||||
assert element is not None
|
||||
assert element["attributes"] == {
|
||||
"label": "A",
|
||||
"title": "Titre de la carte",
|
||||
"description": "Description de la carte.",
|
||||
}
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert html == (
|
||||
f'<div class="docCard" data-element-id="{element_id}" data-kind="carte">'
|
||||
f'<div class="docCardLabel">A</div>'
|
||||
f'<div class="docCardTitle">Titre de la carte</div>'
|
||||
f'<div class="docCardDescription">Description de la carte.</div>'
|
||||
f"</div>"
|
||||
)
|
||||
|
||||
|
||||
def test_carte_escapes_all_fields(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "carte", page_id=page_id)
|
||||
doc_engine.update_document_element_attributes(
|
||||
slug, element_id, {"label": "<b>", "title": "<i>", "description": "<script>alert(1)</script>"}
|
||||
)
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "<script>" not in html
|
||||
assert "<b>" not in html
|
||||
assert "<i>" not in html
|
||||
|
||||
|
||||
def test_image_default_attributes_include_empty_svg_markup(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "image", page_id=page_id)
|
||||
element = doc_engine.get_document_element(slug, element_id)
|
||||
assert element is not None
|
||||
assert element["attributes"] == {"src": "", "alt": "", "svg_markup": ""}
|
||||
|
||||
|
||||
def test_image_with_svg_markup_takes_priority_over_src(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "image", page_id=page_id)
|
||||
doc_engine.update_document_element_attributes(
|
||||
slug,
|
||||
element_id,
|
||||
{"src": "https://exemple.test/photo.png", "alt": "", "svg_markup": '<svg><circle cx="5" cy="5" r="3"/></svg>'},
|
||||
)
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "<img" not in html
|
||||
assert f'<div class="docImage" data-element-id="{element_id}" data-kind="image">' in html
|
||||
assert '<circle cx="5" cy="5" r="3">' in html or '<circle cx="5" cy="5" r="3"/>' in html
|
||||
|
||||
|
||||
def test_image_svg_markup_strips_script_tag(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "image", page_id=page_id)
|
||||
malicious = '<svg onload="alert(1)"><script>alert(2)</script><circle cx="1" cy="1" r="1" onclick="alert(3)"/></svg>'
|
||||
doc_engine.update_document_element_attributes(slug, element_id, {"src": "", "alt": "", "svg_markup": malicious})
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert "<script>" not in html
|
||||
assert "onload" not in html
|
||||
assert "onclick" not in html
|
||||
assert "alert(" not in html
|
||||
|
||||
|
||||
def test_bouton_default_attributes_include_empty_attachment_fields(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
element = doc_engine.get_document_element(slug, element_id)
|
||||
assert element is not None
|
||||
assert element["attributes"] == {
|
||||
"label": "Bouton",
|
||||
"target": "",
|
||||
"attachment_stored_name": "",
|
||||
"attachment_filename": "",
|
||||
}
|
||||
|
||||
|
||||
def test_bouton_with_attachment_filename_renders_data_attribute(tmp_support_slug_cleanup: Any) -> None:
|
||||
slug, page_id = _new_support(tmp_support_slug_cleanup)
|
||||
element_id = doc_engine.add_document_element(slug, "bouton", page_id=page_id)
|
||||
doc_engine.update_document_element_attributes(
|
||||
slug,
|
||||
element_id,
|
||||
{
|
||||
"label": "Télécharger",
|
||||
"target": "",
|
||||
"attachment_stored_name": "abc123.pdf",
|
||||
"attachment_filename": "fiche-consignes.pdf",
|
||||
},
|
||||
)
|
||||
|
||||
html = doc_engine.render_document(doc_engine.list_document_elements(slug, page_id))
|
||||
assert 'data-attachment-filename="fiche-consignes.pdf"' in html
|
||||
|
||||
Reference in New Issue
Block a user