From 5cd47aea818b0dc816b68ebe57604e4718d548f1 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Fri, 19 Jun 2026 16:34:07 -0700 Subject: [PATCH 1/2] fix(awards): clean section anchors, paper-section counts, tidy name spacing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Section anchor IDs are now clean/shareable (#student-awards, #best-paper-awards) instead of #section-...-heading. - Best/Other Paper Award headings show a count, e.g. 'Best Paper Awards (12)'. - Recipient/project lists no longer render a stray space before the comma ('Name, Project' not 'Name , Project') — was template whitespace between the loops. - Adds regression tests for the spacing and the anchor/count changes. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../snippets/display_award_snippet.html | 10 +++--- website/templates/website/awards.html | 22 ++++++------- website/tests/test_award.py | 33 +++++++++++++++++++ 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/website/templates/snippets/display_award_snippet.html b/website/templates/snippets/display_award_snippet.html index 32ead406..520bdf46 100644 --- a/website/templates/snippets/display_award_snippet.html +++ b/website/templates/snippets/display_award_snippet.html @@ -54,13 +54,11 @@

{% if award.organization %}

{{ award.organization }}

{% endif %} + {# Recipients, then publicly-visible projects (private ones omitted, #1300). The + endfor/connector/for junctions are kept whitespace-tight on one line so the + output reads "Name, Project" and never "Name , Project". #}

- {% for person in award.recipients.all %}{{ person.get_full_name }}{% if not forloop.last %}, {% endif %}{% endfor %} - - {% if award.recipients.exists and award.get_visible_projects.exists %}, {% endif %} - - {# Only list publicly-visible projects so private projects aren't named here (#1300) #} - {% for project in award.get_visible_projects %}{{ project.name }}{% if not forloop.last %}, {% endif %}{% endfor %} + {% for person in award.recipients.all %}{{ person.get_full_name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% if award.recipients.exists and award.get_visible_projects.exists %}, {% endif %}{% for project in award.get_visible_projects %}{{ project.name }}{% if not forloop.last %}, {% endif %}{% endfor %}

{% if award.description %} diff --git a/website/templates/website/awards.html b/website/templates/website/awards.html index 53058fd2..5ee29611 100644 --- a/website/templates/website/awards.html +++ b/website/templates/website/awards.html @@ -51,10 +51,10 @@

Makeability Lab Awards

{% for section in distinction_sections %} -
-

+
+

{{ section.label }} - @@ -71,10 +71,10 @@

-
-

- Best Paper Awards - +

+ Best Paper Awards ({{ best_paper_pubs|length }}) + @@ -90,10 +90,10 @@

-
-

- Other Paper Awards - +

+ Other Paper Awards ({{ other_award_pubs|length }}) + diff --git a/website/tests/test_award.py b/website/tests/test_award.py index 67e573ba..755a1beb 100644 --- a/website/tests/test_award.py +++ b/website/tests/test_award.py @@ -11,6 +11,7 @@ than in a SimpleTestCase. """ +import re from datetime import date from django.urls import reverse @@ -115,3 +116,35 @@ def test_awards_page_renders_card_with_year_and_anchor_kind(self): self.assertIn("award-card", html) self.assertIn("award-card--medal", html) # faculty honor -> medal anchor self.assertIn("2017", html) # prominent year is rendered + + def test_recipient_and_project_join_has_no_stray_space(self): + # Regression: the recipient/project connector rendered as "Name , Project" + # due to template whitespace between the two loops. + person = self.make_person(first_name="Chu", last_name="Li") + project = self.make_project(name="AltGeoViz", short_name="altgeoviz", is_visible=True) + award = Award.objects.create(title="People's Choice Award", date=date(2024, 10, 29), + award_type=AwardType.PROJECT_AWARD) + award.recipients.set([person]) + award.projects.set([project]) + + html = self.client.get(reverse("website:awards")).content.decode() + # Strip tags (names sit inside ), then collapse whitespace, so we + # compare the *visible* text the way a reader sees it. + text = re.sub(r"\s+", " ", re.sub(r"<[^>]+>", "", html)) + self.assertIn("Chu Li, AltGeoViz", text) + self.assertNotIn("Chu Li , AltGeoViz", text) + + def test_section_anchors_are_clean_and_paper_sections_show_counts(self): + self.make_publication(title="A Great Paper", year=2020, award="Best Paper Award") + Award.objects.create(title="A Faculty Honor", date=date(2017, 5, 1), + award_type=AwardType.FACULTY_HONOR).recipients.set([self.make_person()]) + + html = self.client.get(reverse("website:awards")).content.decode() + # Clean, shareable anchor IDs (no verbose 'section-...-heading'). + self.assertIn('id="faculty-honors"', html) + self.assertIn('id="best-paper-awards"', html) + self.assertNotIn("section-faculty-honors-heading", html) + self.assertNotIn("best-paper-awards-heading", html) + # Paper-section counts. + self.assertIn("Best Paper Awards (1)", html) + self.assertIn("Other Paper Awards (0)", html) From ce577d8ed0dfdf279d5fb7ac0a9be2058e44a3c0 Mon Sep 17 00:00:00 2001 From: Jon Froehlich Date: Fri, 19 Jun 2026 16:34:07 -0700 Subject: [PATCH 2/2] chore(awards): retire import_awards from deploy; bump to 2.14.1 The one-time backfill has run on test + prod, so remove its docker-entrypoint.sh step (stops re-running every deploy and resurrecting admin-deleted awards). The import_awards command + tests stay in the repo, unwired and re-runnable. Co-Authored-By: Claude Opus 4.8 (1M context) --- docker-entrypoint.sh | 5 ----- makeabilitylab/settings.py | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 065ad2f1..59b0b948 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -125,11 +125,6 @@ echo "4.8 Running 'python manage.py recompute_url_names' to de-collide historica echo "******************************************" python manage.py recompute_url_names -echo "****************** STEP 4.9/5: docker-entrypoint.sh ************************" -echo "4.9 Running 'python manage.py import_awards' to backfill missing Awards (idempotent)" -echo "******************************************" -python manage.py import_awards - # echo "****************** STEP 4.3/5: docker-entrypoint.sh ************************" # echo "4.3 Running 'python manage.py rename_person_images' to rename person images" # echo "******************************************" diff --git a/makeabilitylab/settings.py b/makeabilitylab/settings.py index 4b71dc3b..4bbc4d14 100644 --- a/makeabilitylab/settings.py +++ b/makeabilitylab/settings.py @@ -86,8 +86,8 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # Makeability Lab Global Variables, including Makeability Lab version -ML_WEBSITE_VERSION = "2.14.0" # Keep this updated with each release and also change the short description below -ML_WEBSITE_VERSION_DESCRIPTION = "Feature: redesigned Awards page. Each award now renders as a card with a category-specific visual anchor — recipient photo (student awards), project thumbnail (project awards), or a gold medal icon (faculty honors), with an optional uploaded emblem (new Award.badge field) overriding any of these — led by a prominent golden-orange year badge. A new idempotent import_awards management command (wired into docker-entrypoint.sh) backfills ~27 people/project/faculty awards mined from the news archive + CV that were missing from the Awards page, and corrects the mis-dated Facilitators' Choice (PrototypAR) entry. Paper awards stay on Publication.award; the one gap ('Playing on Hard Mode') is tracked in #1354. /awards/ added to the Pa11y scan set." +ML_WEBSITE_VERSION = "2.14.1" # Keep this updated with each release and also change the short description below +ML_WEBSITE_VERSION_DESCRIPTION = "Patch: Awards page polish. Section headings now use clean, shareable anchor IDs (e.g. #student-awards, #best-paper-awards instead of #section-...-heading); recipient/project lists no longer render a stray space before the comma ('Name, Project'); and the Best/Other Paper Award headings show a count, e.g. 'Best Paper Awards (12)'. Also retires the one-time import_awards step from the deploy sequence now that the backfill has run on test + prod — the management command stays in the repo (unwired, re-runnable) so a future rebuild can replay it." DATE_MAKEABILITYLAB_FORMED = datetime.date(2012, 1, 1) # Date Makeability Lab was formed MAX_BANNERS = 7 # Maximum number of banners on a page