fix: inline device images as data URIs in offline SVG export

strip_svg_hyperlinks() removed every href, including on <image>
elements that reference device-type photos, leaving devices with
images blank in the exported file. Non-anchor hrefs (currently only
<image>) are now resolved through an optional image_loader callback
and embedded as base64 data URIs instead of being stripped; anchor
unwrapping is unchanged. RackElevationOfflineSVGView wires this up to
NetBox's MEDIA storage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 15:20:43 +02:00
co-authored by Claude Sonnet 5
parent 23acebcf17
commit ead171d546
5 changed files with 102 additions and 14 deletions
+40 -2
View File
@@ -19,16 +19,54 @@ class StripSvgHyperlinksTest(SimpleTestCase):
self.assertNotIn("href", result)
self.assertIn("<rect", result)
def test_removes_href_on_non_anchor_elements(self):
def test_removes_href_on_non_image_non_anchor_elements(self):
svg = (
'<svg xmlns="http://www.w3.org/2000/svg" '
'xmlns:xlink="http://www.w3.org/1999/xlink">'
'<image xlink:href="/static/logo.png" href="/static/logo.png"/>'
'<use xlink:href="#some-symbol" href="#some-symbol"/>'
"</svg>"
)
result = strip_svg_hyperlinks(svg)
self.assertNotIn("href", result)
self.assertIn("<use", result)
def test_leaves_image_href_untouched_without_a_loader(self):
svg = (
'<svg xmlns="http://www.w3.org/2000/svg" '
'xmlns:xlink="http://www.w3.org/1999/xlink">'
'<image xlink:href="/media/devicetype-images/example.png"/>'
"</svg>"
)
result = strip_svg_hyperlinks(svg)
self.assertIn("/media/devicetype-images/example.png", result)
def test_replaces_image_href_with_data_uri_from_loader(self):
svg = (
'<svg xmlns="http://www.w3.org/2000/svg" '
'xmlns:xlink="http://www.w3.org/1999/xlink">'
'<image xlink:href="/media/devicetype-images/example.png"/>'
"</svg>"
)
result = strip_svg_hyperlinks(svg, image_loader=lambda href: "data:image/png;base64,AAAA")
self.assertIn("data:image/png;base64,AAAA", result)
self.assertNotIn("/media/devicetype-images/example.png", result)
def test_drops_image_href_when_loader_cannot_resolve_it(self):
svg = (
'<svg xmlns="http://www.w3.org/2000/svg" '
'xmlns:xlink="http://www.w3.org/1999/xlink">'
'<image xlink:href="/media/devicetype-images/missing.png"/>'
"</svg>"
)
result = strip_svg_hyperlinks(svg, image_loader=lambda href: None)
self.assertNotIn("href", result)
self.assertIn("<image", result)