display_name → at_handle for every user-rendering point around the recent-activity surfaces: scroll.html actor <strong>, Most Recent Scroll applet actor <strong>, My Games row body actor prefix, My Scrolls row body actor prefix, My Buds page bud-name span, navbar identity, _bud_panel.html data-sharer-name (consumed by the dynamic post-line-author append on share success) — at_handle was always the right filter for these slots: it produces @<username> when the user has set one, falling back to the truncated email (which already carries an @) so we don't double-prefix; the _my_buds_applet_item.html row was already on at_handle from the 3-col sprint, so this commit just brings the rest of the surfaces in line; _navbar.html swap also drops the literal @ that prefixed {{ user|display_name }} — that literal predated at_handle + worked for users w. usernames (gave @disco) but produced @<email>@<domain> for users w. no username yet; navbar wait_to_be_logged_in(email) FT helper keeps working since the email still appears as a substring whether rendered as @disco@test.io (old, no username) or disco@test.io (new); _bud_add_panel.html's client-side _appendBudEntry JS gains an inline at_handle mirror — display.indexOf('@') >= 0 ? display : '@' + display — since the server's add_bud response packs username or email under the username key (semantic mismatch w. the key name but stable) so the JS has to detect the email case itself; test_bill_my_buds.py two .bud-name text assertions ("alice""@alice") updated for the new prefix; 931 ITs + targeted FT regression on test_bill_my_buds + test_core_navbar + test_core_login green
Some checks failed
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline failed

This commit is contained in:
Disco DeDisco
2026-05-13 01:09:43 -04:00
parent f7fa250804
commit db10f345e4
9 changed files with 18 additions and 11 deletions

View File

@@ -25,7 +25,9 @@ class MyBudsPageTest(FunctionalTest):
entry = self.wait_for(
lambda: self.browser.find_element(By.CSS_SELECTOR, ".bud-entry .bud-name")
)
self.assertEqual(entry.text, "alice")
# Bud names render via `at_handle` filter — `@<username>` w. an
# `@` prefix on users w. a username; truncated email otherwise.
self.assertEqual(entry.text, "@alice")
def test_empty_state_when_no_buds(self):
self.browser.get(self.live_server_url + "/billboard/my-buds/")
@@ -44,12 +46,12 @@ class MyBudsPageTest(FunctionalTest):
ok = self.browser.find_element(By.CSS_SELECTOR, "#id_bud_panel .btn.btn-confirm")
ok.click()
# New entry appears w. alice's username (not the bare email)
# New entry appears w. alice's @-prefixed handle (not the bare email)
self.wait_for(lambda: self.assertEqual(
self.browser.find_element(
By.CSS_SELECTOR, f".bud-entry[data-bud-id='{self.alice.id}'] .bud-name"
).text,
"alice",
"@alice",
))
# Server-side persisted
self.wait_for(lambda: self.assertIn(

View File

@@ -11,7 +11,7 @@
{% for event in recent_events %}
<div class="drama-event {% if event.actor == viewer %}mine{% elif event.actor %}theirs{% else %}system{% endif %}">
<span class="drama-event-body{% if event.struck %} struck{% endif %}">
{% if event.actor %}<strong>{{ event.actor|display_name }}</strong>{% endif %}
{% if event.actor %}<strong>{{ event.actor|at_handle }}</strong>{% endif %}
{{ event.to_prose|safe }}
</span>
<time class="drama-event-time" datetime="{{ event.timestamp|date:'c' }}">

View File

@@ -46,7 +46,12 @@
li.dataset.budId = bud.id;
var name = document.createElement('span');
name.className = 'bud-name';
name.textContent = bud.username;
// Mirror the `at_handle` template filter: prefix `@` on plain
// usernames; leave the value untouched if it already contains
// `@` (the server falls back to email when username is unset,
// and emails don't take the prefix).
var display = bud.username || '';
name.textContent = display.indexOf('@') >= 0 ? display : '@' + display;
li.appendChild(name);
var buffer = list.querySelector('.bud-entry-buffer');
if (buffer) list.insertBefore(li, buffer);

View File

@@ -16,7 +16,7 @@
</button>
<div id="id_bud_panel"
data-sharer-name="{% if request.user.is_authenticated %}{{ request.user|display_name }}{% endif %}">
data-sharer-name="{% if request.user.is_authenticated %}{{ request.user|at_handle }}{% endif %}">
<input id="id_recipient"
name="recipient"
type="text"

View File

@@ -1,4 +1,4 @@
{% load lyric_extras %}
<li class="applet-list-entry bud-entry" data-bud-id="{{ item.id }}">
<span class="bud-name">{{ item|display_name }}</span>
<span class="bud-name">{{ item|at_handle }}</span>
</li>

View File

@@ -8,7 +8,7 @@
<li class="applet-list-entry row-3col">
<a href="{% url 'billboard:scroll' item.id %}" class="row-title">{{ item.name|truncate_title }}</a>
{% if item.latest_event %}
<span class="row-body">{% if item.latest_event.actor %}{{ item.latest_event.actor|display_name }} {% endif %}{{ item.latest_event.to_prose|striptags }}</span>
<span class="row-body">{% if item.latest_event.actor %}{{ item.latest_event.actor|at_handle }} {% endif %}{{ item.latest_event.to_prose|striptags }}</span>
<time class="row-ts" datetime="{{ item.latest_event.timestamp|date:'c' }}">{{ item.latest_event.timestamp|relative_ts }}</time>
{% endif %}
</li>

View File

@@ -7,7 +7,7 @@
<li class="applet-list-entry row-3col">
<a href="{% url 'epic:gatekeeper' item.id %}" class="row-title">{{ item.name|truncate_title }}</a>
{% if item.latest_event %}
<span class="row-body">{% if item.latest_event.actor %}{{ item.latest_event.actor|display_name }} {% endif %}{{ item.latest_event.to_prose|striptags }}</span>
<span class="row-body">{% if item.latest_event.actor %}{{ item.latest_event.actor|at_handle }} {% endif %}{{ item.latest_event.to_prose|striptags }}</span>
<time class="row-ts" datetime="{{ item.latest_event.timestamp|date:'c' }}">{{ item.latest_event.timestamp|relative_ts }}</time>
{% endif %}
</li>

View File

@@ -11,7 +11,7 @@
Logged in as
</span>
<span class="navbar-identity">
@{{ user|display_name }}
{{ user|at_handle }}
</span>
</div>
<form method="POST" action="{% url "logout" %}">

View File

@@ -3,7 +3,7 @@
{% for event in events %}
<div class="drama-event {% if event.actor == viewer %}mine{% elif event.actor %}theirs{% else %}system{% endif %}" data-label="{% if event.struck %}redact{% else %}frame{% endif %}">
<span class="drama-event-body{% if event.struck %} struck{% endif %}">
{% if event.actor %}<strong>{{ event.actor|display_name }}</strong>{% endif %}
{% if event.actor %}<strong>{{ event.actor|at_handle }}</strong>{% endif %}
{{ event.to_prose|safe }}
</span>
<time class="drama-event-time" datetime="{{ event.timestamp|date:'c' }}">