Skip to content
Merged
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
33 changes: 11 additions & 22 deletions apps/sponsors/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,35 +736,24 @@ def get_sponsor_landing_page_url(self, obj):
@admin.display(description="Web Logo")
def get_sponsor_web_logo(self, obj):
"""Render and return the sponsor's web logo as a thumbnail image."""
img = obj.sponsor.web_logo
if not img:
return "---"
if img.name and img.name.lower().endswith(".svg"):
return format_html(
'<img src="{}" style="max-width:150px;max-height:150px"/>',
img.url,
)
html = "{% load thumbnail %}{% thumbnail img '150x150' format='PNG' quality=100 as im %}<img src='{{ im.url}}'/>{% endthumbnail %}"
html = "{% load thumbnail %}{% thumbnail sponsor.web_logo '150x150' format='PNG' quality=100 as im %}<img src='{{ im.url}}'/>{% endthumbnail %}"
template = Template(html)
context = Context({"img": img})
return mark_safe(template.render(context)) # noqa: S308
context = Context({"sponsor": obj.sponsor})
html = template.render(context)
return mark_safe(html) # noqa: S308
Comment on lines +739 to +743
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

get_sponsor_web_logo now always renders a {% thumbnail sponsor.web_logo %} block without guarding for empty/missing files. In this codebase, Sponsor instances can exist without an actual web_logo file (e.g., tests use model_bakery without _create_files=True), which will cause sorl-thumbnail to raise and break the admin changelist/detail rendering. Add an early return (e.g., "---") when obj.sponsor.web_logo is falsy, or otherwise handle missing files before invoking thumbnail.

Copilot uses AI. Check for mistakes.

@admin.display(description="Print Logo")
def get_sponsor_print_logo(self, obj):
"""Render and return the sponsor's print logo as a thumbnail image."""
img = obj.sponsor.print_logo
if not img:
return "---"
if img.name and img.name.lower().endswith(".svg"):
return format_html(
'<img src="{}" style="max-width:150px;max-height:150px"/>',
img.url,
html = "---"
if img:
template = Template(
"{% load thumbnail %}{% thumbnail img '150x150' format='PNG' quality=100 as im %}<img src='{{ im.url}}'/>{% endthumbnail %}"
)
Comment on lines +751 to 753
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore SVG passthrough for print logos in admin

Sponsors can still upload SVG print logos (apps/sponsors/models/sponsors.py:52-59, and apps/sponsors/tests/test_forms.py:427-440 covers that path), but this revert now sends every non-empty print_logo through {% thumbnail ... format='PNG' %} again. That removes the only SVG bypass, so opening the sponsorship admin views for any sponsor using the documented SVG format can reproduce the original Sentry failure instead of rendering the uploaded file.

Useful? React with 👍 / 👎.

template = Template(
"{% load thumbnail %}{% thumbnail img '150x150' format='PNG' quality=100 as im %}<img src='{{ im.url}}'/>{% endthumbnail %}"
)
context = Context({"img": img})
return mark_safe(template.render(context)) # noqa: S308
context = Context({"img": img})
html = mark_safe(template.render(context)) # noqa: S308
return html
Comment on lines 748 to +756
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

get_sponsor_print_logo thumbnails obj.sponsor.print_logo, but print_logo explicitly allows svg and eps/epsfepsi uploads. With only Pillow/sorl-thumbnail configured, SVG/EPS inputs will fail thumbnail generation and can crash the admin page. Handle non-raster formats explicitly (e.g., render SVG via direct <img src=...> or provide a download link; skip thumbnailing for EPS), and only call {% thumbnail %} for raster images like PNG/JPG.

Copilot uses AI. Check for mistakes.

@admin.display(description="Primary Phone")
def get_sponsor_primary_phone(self, obj):
Expand Down
16 changes: 4 additions & 12 deletions apps/sponsors/templates/sponsors/partials/sponsors-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,14 @@ <h2 class="widget-title" style="text-align: center;">Sponsors</h2>
<p style="text-align: center;">Visionary sponsors help to host Python downloads.</p>
<div style="display: grid; grid-gap: 2em; grid-template-columns: repeat(auto-fit, minmax(150px, 0fr)); align-items: center; justify-content: center; margin-top: 1.5em;">
{% for sponsorship in sponsorships %}
{% thumbnail sponsorship.sponsor.web_logo "x150" format="PNG" quality=100 as im %}
<div style="text-align: center;">
<a href="{{ sponsorship.sponsor.landing_page_url }}" rel="sponsored noopener" target="_blank" style="border-bottom: 0;">
{% if sponsorship.sponsor.web_logo.name|lower|slice:"-4:" == ".svg" %}
<img src="{{ sponsorship.sponsor.web_logo.url }}" alt="{{ sponsorship.sponsor.name }} logo" style="max-height:150px;max-width:150px;height:auto;width:auto;">
{% else %}
{% thumbnail sponsorship.sponsor.web_logo "x150" format="PNG" quality=100 as im %}
<img src="{{ im.url }}" alt="{{ sponsorship.sponsor.name }} logo" style="max-height:150px;max-width:150px;height:auto;width:auto;">
{% endthumbnail %}
{% endif %}
</a>
<p style="margin-top: 0.5em; margin-bottom: 0; font-size: 0.875em; color: #4d4d4d;">{{ sponsorship.sponsor.name }}</p>
</div>
{% endthumbnail %}
{% endfor %}
</div>
{% endcache CACHED_DOWNLOAD_SPONSORS_LIST %}
Expand All @@ -32,15 +28,11 @@ <h2 class="widget-title" style="text-align: center;">Sponsors</h2>
<h3 class="widget-title">Job Board Sponsors</h3>
<div style="display: grid; grid-gap: 1em; grid-template-columns: repeat(auto-fit, minmax(100px, 0fr)); grid-template-rows: repeat(1, minmax(50px, 0fr)); align-items: center; justify-content: center; margin-top: 1em;">
{% for sponsorship in sponsorships %}
{% thumbnail sponsorship.sponsor.web_logo "x100" format="PNG" quality=100 as im %}
<div>
{% if sponsorship.sponsor.web_logo.name|lower|slice:"-4:" == ".svg" %}
<img src="{{ sponsorship.sponsor.web_logo.url }}" alt="{{ sponsorship.sponsor.name }} logo" style="max-height:100px;max-width:100px;height:auto;width:auto;">
{% else %}
{% thumbnail sponsorship.sponsor.web_logo "x100" format="PNG" quality=100 as im %}
<img src="{{ im.url }}" alt="{{ sponsorship.sponsor.name }} logo" style="max-height:100px;max-width:100px;height:auto;width:auto;">
{% endthumbnail %}
{% endif %}
</div>
{% endthumbnail %}
{% endfor %}
</div>
{% endcache CACHED_JOBS_SPONSORS_LIST %}
Expand Down
Loading