Skip to content

Supply url_fetcher to weasyprint to support /media and /static files #9394

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ repos:
- id: check-yaml
- id: mixed-line-ending
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.0
rev: v0.11.2
hooks:
- id: ruff-format
args: [--preview]
Expand All @@ -28,7 +28,7 @@ repos:
--preview
]
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.6.6
rev: 0.6.10
hooks:
- id: pip-compile
name: pip-compile requirements-dev.in
Expand Down Expand Up @@ -70,13 +70,13 @@ repos:
src/frontend/vite.config.ts |
)$
- repo: https://github.com/biomejs/pre-commit
rev: v1.9.4
rev: v2.0.0-beta.1
hooks:
- id: biome-check
additional_dependencies: ["@biomejs/biome@1.9.4"]
files: ^src/frontend/.*\.(js|ts|tsx)$
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.0
rev: v8.24.2
hooks:
- id: gitleaks
language_version: 1.23.6
Expand Down
33 changes: 31 additions & 2 deletions src/backend/InvenTree/report/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io
import os
import sys
from urllib.parse import unquote, urlparse

from django.conf import settings
from django.core.exceptions import ValidationError
Expand All @@ -26,13 +27,14 @@
import report.validators
from common.models import DataOutput
from common.settings import get_global_setting
from InvenTree import config
from InvenTree.helpers_model import get_base_url
from InvenTree.models import MetadataMixin
from plugin import InvenTreePlugin, PluginMixinEnum
from plugin.registry import registry

try:
from weasyprint import HTML
from weasyprint import HTML, default_url_fetcher
except OSError as err: # pragma: no cover
print(f'OSError: {err}')
print("Unable to import 'weasyprint' module.")
Expand All @@ -42,6 +44,31 @@

logger = structlog.getLogger('inventree')

WE_BASE_URL = 'http://localhost'
Copy link
Member

Choose a reason for hiding this comment

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

An issue here is that the request URL may or may not exactly match the server's internal URL, depending on proxying settings. Adding a hard-coded URL here is not a good idea.



def url_fetcher(url: str, timeout=10, ssl_context=None):
"""Function to fetch files for Weasyprint.

Will resolve `/media` and `/static` requests to `MEDIA_ROOT` and `STATIC_ROOT` respectively.

All other requests will fall back to `weasyprint.default_url_fetcher`.
"""
media = config.get_media_dir().resolve()
static = config.get_static_dir().resolve()
if url.startswith(WE_BASE_URL):
# .path always starts with a '/' character, which must be trimmed off.
u = unquote(urlparse(url).path)[1:]
if u.startswith('/media'):
pth = media.parent.joinpath(u).resolve()
if media in pth.parents:
return {'file_obj': open(pth, 'rb')}
elif u.startswith('/static'):
pth = static.parent.joinpath(u).resolve()
if static in pth.parents:
return {'file_obj': open(pth, 'rb')}
return default_url_fetcher(url, timeout=timeout, ssl_context=ssl_context)


def rename_template(instance, filename):
"""Function to rename a report template once uploaded.
Expand Down Expand Up @@ -198,7 +225,9 @@ def render(self, instance, request=None, **kwargs) -> bytes:
bytes: PDF data
"""
html = self.render_as_string(instance, request, **kwargs)
pdf = HTML(string=html).write_pdf()
pdf = HTML(
string=html, url_fetcher=url_fetcher, base_url=WE_BASE_URL
).write_pdf()

return pdf

Expand Down