Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 0 additions & 63 deletions src/backend/InvenTree/InvenTree/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@
from stdimage.models import StdImageField, StdImageFieldFile

from common.currency import currency_code_default
from InvenTree.sanitizer import (
DEAFAULT_ATTRS,
DEFAULT_CSS,
DEFAULT_PROTOCOLS,
DEFAULT_TAGS,
)

logger = structlog.get_logger('inventree')

Expand Down Expand Up @@ -939,63 +933,6 @@ def remove_non_printable_characters(value: str, remove_newline=True) -> str:
return cleaned


def clean_markdown(value: str) -> str:
"""Clean a markdown string.

This function will remove javascript and other potentially harmful content from the markdown string.
"""
import markdown

try:
markdownify_settings = settings.MARKDOWNIFY['default']
except (AttributeError, KeyError):
markdownify_settings = {}

extensions = markdownify_settings.get('MARKDOWN_EXTENSIONS', [])
extension_configs = markdownify_settings.get('MARKDOWN_EXTENSION_CONFIGS', {})

# Generate raw HTML from provided markdown (without sanitizing)
# Note: The 'html' output_format is required to generate self closing tags, e.g. <tag> instead of <tag />
html = markdown.markdown(
value or '',
extensions=extensions,
extension_configs=extension_configs,
output_format='html',
)

# nh3 sanitizer settings
whitelist_tags = markdownify_settings.get('WHITELIST_TAGS', DEFAULT_TAGS)
whitelist_attrs = markdownify_settings.get('WHITELIST_ATTRS', DEAFAULT_ATTRS)
whitelist_styles = markdownify_settings.get('WHITELIST_STYLES', DEFAULT_CSS)
whitelist_protocols = markdownify_settings.get(
'WHITELIST_PROTOCOLS', DEFAULT_PROTOCOLS
)

# Convert bleach-style attributes (list or dict) to nh3-compatible dict format
if isinstance(whitelist_attrs, (list, tuple, set, frozenset)):
attrs_dict = {'*': set(whitelist_attrs)}
elif isinstance(whitelist_attrs, dict):
attrs_dict = {tag: set(allowed) for tag, allowed in whitelist_attrs.items()}
else:
attrs_dict = None

# Clean the HTML content (for comparison). This must be the same as the original content
clean_html = nh3.clean(
html,
tags=set(whitelist_tags),
attributes=attrs_dict,
url_schemes=set(whitelist_protocols),
filter_style_properties=set(whitelist_styles),
link_rel=None,
strip_comments=True,
)

if html != clean_html:
raise ValidationError(_('Data contains prohibited markdown content'))

return value


def hash_barcode(barcode_data: str) -> str:
"""Calculate a 'unique' hash for a barcode string.

Expand Down
11 changes: 1 addition & 10 deletions src/backend/InvenTree/InvenTree/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@
import data_exporter.mixins
import importer.mixins
from InvenTree.fields import InvenTreeNotesField, OutputConfiguration
from InvenTree.helpers import (
clean_markdown,
remove_non_printable_characters,
strip_html_tags,
)
from InvenTree.helpers import remove_non_printable_characters, strip_html_tags
from InvenTree.schema import schema_for_view_output_options
from InvenTree.serializers import FilterableSerializerMixin

Expand Down Expand Up @@ -56,7 +52,6 @@ def clean_string(self, field: str, data: str) -> str:

# By default, newline characters are removed
remove_newline = True
is_markdown = False

try:
if hasattr(self, 'serializer_class'):
Expand All @@ -69,7 +64,6 @@ def clean_string(self, field: str, data: str) -> str:
for field_type in allow_newline:
if issubclass(type(field_base), field_type[0]):
remove_newline = False
is_markdown = field_type[1]
break

except AttributeError:
Expand All @@ -83,9 +77,6 @@ def clean_string(self, field: str, data: str) -> str:

cleaned = strip_html_tags(cleaned, field_name=field)

if is_markdown:
cleaned = clean_markdown(cleaned)

return cleaned

def clean_data(self, data: dict) -> dict:
Expand Down
44 changes: 0 additions & 44 deletions src/backend/InvenTree/InvenTree/setting/markdown.py

This file was deleted.

17 changes: 1 addition & 16 deletions src/backend/InvenTree/InvenTree/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,7 @@
from users.oauth2_scopes import oauth2_scopes

from . import config
from .setting import (
db_backend,
ldap,
locales,
markdown,
spectacular,
storages,
tracing,
worker,
)
from .setting import db_backend, ldap, locales, spectacular, storages, tracing, worker

try:
import django_stubs_ext
Expand Down Expand Up @@ -341,7 +332,6 @@
'corsheaders', # Cross-origin Resource Sharing for DRF
'django_cleanup.apps.CleanupConfig', # Automatically delete orphaned MEDIA files
'mptt', # Modified Preorder Tree Traversal
'markdownify', # Markdown template rendering
'djmoney', # django-money integration
'djmoney.contrib.exchange', # django-money exchange rates
'error_report', # Error reporting in the admin interface
Expand Down Expand Up @@ -1066,11 +1056,6 @@
)
# endregion auth

# Markdownify configuration
# Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html

MARKDOWNIFY = markdown.markdownify_config()

# Ignore these error types for in-database error logging
IGNORED_ERRORS = [Http404, HttpResponseGone, django.core.exceptions.PermissionDenied]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}

{% block page_margin %}
margin: 2cm;
Expand Down Expand Up @@ -172,7 +171,7 @@ <h3>
<h3>{% trans "Notes" %}</h3>

{% if build.notes %}
{{ build.notes|markdownify }}
{{ build.notes }}
{% endif %}
Comment on lines 173 to 175
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the template and show the surrounding lines for context
sed -n '130,210p' src/backend/InvenTree/report/templates/report/inventree_build_order_report.html

# Inspect mixins around the cited newline-preservation logic
sed -n '1,140p' src/backend/InvenTree/InvenTree/mixins.py

# Find where build.notes is set/derived (search across backend for ".notes" in build order report context)
rg -n "build\.notes|notes\s*=" src/backend/InvenTree | head -n 200

# Search for markdownify usage/removal in the report rendering pipeline
rg -n "markdownify|markdown|linebreaksbr|linebreaks|preform|pre\s*|" src/backend/InvenTree/report src/backend/InvenTree/InvenTree | head -n 200

# Find definition/usage of InvenTreeNotesField
rg -n "InvenTreeNotesField" src/backend/InvenTree | head -n 200

Repository: matmair/InvenTree

Length of output: 36603


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect InvenTreeNotesField implementation
sed -n '150,280p' src/backend/InvenTree/fields.py

# Inspect build model notes field to see how it stores/represents notes
sed -n '1180,1285p' src/backend/InvenTree/build/models.py

# Search for how notes are rendered in templates elsewhere
rg -n "build\.notes|\.notes\b" src/backend/InvenTree/report/templates | head -n 200

rg -n "linebreaksbr|markdownify|markdown|safe\W*\|.*safe" src/backend/InvenTree/report/templates | head -n 200

# Search globally for use of linebreaksbr with notes fields
rg -n "linebreaksbr" src/backend/InvenTree | head -n 200

Repository: matmair/InvenTree

Length of output: 136


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect InvenTreeNotesField implementation (correct path)
sed -n '180,270p' src/backend/InvenTree/InvenTree/fields.py

# Inspect build model notes field usage (for representation hints)
sed -n '1210,1275p' src/backend/InvenTree/build/models.py

# Inspect template(s) for how notes are rendered elsewhere
rg -n "build\.notes|\.notes\b" src/backend/InvenTree/report/templates | head -n 200

# Check whether any note-related templates already use linebreaksbr/markdown/linebreak conversion
rg -n "linebreaksbr|markdownify|markdown|<br\s*/?>|pre\s*|white-space" src/backend/InvenTree/report/templates | head -n 200

# Find any template usage of |linebreaksbr globally
rg -n "\|linebreaksbr" src/backend/InvenTree | head -n 200

# Find any template usage of markdownify globally in report/templates
rg -n "markdownify" src/backend/InvenTree/report/templates | head -n 200

Repository: matmair/InvenTree

Length of output: 10207


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show more context around the notes block in the build order report template
sed -n '1,120p' src/backend/InvenTree/report/templates/report/inventree_build_order_report.html
sed -n '150,200p' src/backend/InvenTree/report/templates/report/inventree_build_order_report.html

# Check for any filters/tags used in templates for notes rendering (linebreaksbr, markdownify, etc.)
rg -n "markdownify|linebreaksbr|linebreaks|pre-wrap|white-space:\s*pre|<pre|<br\s*/?>" src/backend/InvenTree/report/templates/report | head -n 200

# Search globally for markdownify usage in backend
rg -n "markdownify" src/backend/InvenTree | head -n 200

# Search globally for markdown filter usage (could be custom)
rg -n "markdown\s*ify|markdown\s*\(" src/backend/InvenTree | head -n 200

# Search for any custom template filter applying markdown to notes fields
rg -n "templatetag|register\.filter|`@register`\.filter" src/backend/InvenTree | head -n 200

Repository: matmair/InvenTree

Length of output: 3622


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the base report template CSS for whitespace handling
sed -n '1,140p' src/backend/InvenTree/report/templates/report/inventree_report_base.html

# Search for CSS rules or template filters affecting whitespace/newlines in report templates
rg -n "white-space\s*:\s*pre|white-space\s*:\s*pre-wrap|pre-wrap|linebreaksbr|newline" src/backend/InvenTree/report/templates/report/inventree_report_base.html src/backend/InvenTree/report/templates/report -S

# Inspect inventree_extras templatetags for any markdown/linebreak helper
fd -i "inventree_extras" src/backend/InvenTree -a 2>/dev/null || true
fd -i "inventree_extras\.py" src/backend/InvenTree -a 2>/dev/null || true
fd -i "*extras*" src/backend/InvenTree/report src/backend/InvenTree -a 2>/dev/null | head

# Locate the template tag implementation file and inspect for filters like markdownify/linebreaksbr
rg -n "register\.filter|markdownify|linebreaksbr|linebreak" src/backend/InvenTree -S --glob='*.py' | head -n 200

Repository: matmair/InvenTree

Length of output: 2439


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect helper functions used by CleanMixin
rg -n "def remove_non_printable_characters" -S src/backend/InvenTree | head -n 20
rg -n "def strip_html_tags" -S src/backend/InvenTree | head -n 20

# Show implementations
python3 - <<'PY'
import subprocess, textwrap, os, sys, re, json, pathlib
PY

Repository: matmair/InvenTree

Length of output: 300


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact implementations for newline/HTML stripping behavior
sed -n '860,980p' src/backend/InvenTree/InvenTree/helpers.py

Repository: matmair/InvenTree

Length of output: 3865


Preserve line breaks in build order report notes

build.notes is rendered as raw text ({{ build.notes }}), so any \n preserved for InvenTreeNotesField collapses in normal HTML flow, flattening multi-line notes in the generated report.

Suggested fix
 {% if build.notes %}
-{{ build.notes }}
+{{ build.notes|linebreaksbr }}
 {% endif %}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{% if build.notes %}
{{ build.notes|markdownify }}
{{ build.notes }}
{% endif %}
{% if build.notes %}
{{ build.notes|linebreaksbr }}
{% endif %}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/backend/InvenTree/report/templates/report/inventree_build_order_report.html`
around lines 173 - 175, In the template inventree_build_order_report.html the
build.notes block currently renders raw text ({{ build.notes }}) which collapses
newline characters; update the template to render notes with preserved line
breaks (e.g., use the Django template filter linebreaksbr: {{
build.notes|linebreaksbr }} or an equivalent nl2br-style filter) so multi-line
InvenTreeNotesField content appears with line breaks in the generated report.


{% endblock page_content %}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}

{% block page_margin %}
margin: 2cm;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}

{% block header_content %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}

{% block header_content %}
<img class='logo' src='{% company_image customer %}' alt="{{ customer }}" width='150'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}

{% block header_content %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}

{% block header_content %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% load markdownify %}

{% block header_content %}

Expand Down
22 changes: 0 additions & 22 deletions src/backend/requirements-3.14.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,6 @@ bcrypt==5.0.0 \
# via
# -c src/backend/requirements.txt
# paramiko
bleach==4.1.0 \
--hash=sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da \
--hash=sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994
# via
# -c src/backend/requirements.txt
# django-markdownify
blessed==1.42.0 \
--hash=sha256:34b460b77562ed21f807cfd7c527b983b0cc300c98810c8076f283b7bcd45ba7 \
--hash=sha256:f96c4a6dc664b48e0b832fa732acc16df67abd30f0ec35babf99025982f21852
Expand Down Expand Up @@ -535,7 +529,6 @@ django==5.2.14 \
# django-flags
# django-ical
# django-js-asset
# django-markdownify
# django-money
# django-oauth-toolkit
# django-otp
Expand Down Expand Up @@ -631,12 +624,6 @@ django-maintenance-mode==0.22.0 \
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
django-markdownify==0.9.1 \
--hash=sha256:06ff2994ff09ce030b50de8c6fc5b89b9c25a66796948aff55370716ca1233af \
--hash=sha256:24ba68b8a5996b6ec9632d11a3fd2e7159cb7e6becd3104e0a9372b5a2a148ef
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
django-money==3.6.0 \
--hash=sha256:94402f2831f2726b94ef2da35b4059441b4c0aedfc47b312472200d4ffdf8d73 \
--hash=sha256:a8d249bf3ce6ad7fb953530c920cc85ea7f1137c0fde747a74204ea24ec97ab1
Expand Down Expand Up @@ -1178,12 +1165,6 @@ lxml==6.1.1 \
# -c src/backend/requirements.txt
# python3-saml
# xmlsec
markdown==3.10.2 \
--hash=sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950 \
--hash=sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36
# via
# -c src/backend/requirements.txt
# django-markdownify
markupsafe==3.0.3 \
--hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \
--hash=sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a \
Expand Down Expand Up @@ -1479,7 +1460,6 @@ packaging==26.2 \
--hash=sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661
# via
# -c src/backend/requirements.txt
# bleach
# gunicorn
# opentelemetry-instrumentation
paramiko==5.0.0 \
Expand Down Expand Up @@ -2119,7 +2099,6 @@ six==1.17.0 \
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
# via
# -c src/backend/requirements.txt
# bleach
# python-dateutil
sqlparse==0.5.5 \
--hash=sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba \
Expand Down Expand Up @@ -2215,7 +2194,6 @@ webencodings==0.5.1 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
# via
# -c src/backend/requirements.txt
# bleach
# cssselect2
# tinycss2
# tinyhtml5
Expand Down
1 change: 0 additions & 1 deletion src/backend/requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ django-flags # Feature flags
django-ical # iCal export for calendar views
django-maintenance-mode # Shut down application while reloading etc.
django-mailbox # Email scraping
django-markdownify # Markdown rendering
django-money # Django app for currency management
django-mptt # Modified Preorder Tree Traversal
django-redis>=5.0.0 # Redis integration
Expand Down
Loading
Loading