Lagt til av
{#if activity.owner_username}
diff --git a/frontend/src/components/Home.svelte b/frontend/src/components/Home.svelte
index fe75953..7d0b4e2 100644
--- a/frontend/src/components/Home.svelte
+++ b/frontend/src/components/Home.svelte
@@ -117,8 +117,11 @@
{:else if session.user}
- Velkommen, {session.user.display_name?.trim() || session.user.email}.
- Her er aktivitetene dine for vinteren.
+ {#if session.user.display_name?.trim()}
+ Velkommen, {session.user.display_name}. Her er aktivitetene dine for vinteren.
+ {:else}
+ Her er aktivitetene dine for vinteren.
+ {/if}
{#if !showForm && !editing}
diff --git a/server/activities.ts b/server/activities.ts
index a9bac9b..2dc5a3b 100644
--- a/server/activities.ts
+++ b/server/activities.ts
@@ -66,16 +66,29 @@ function heartsFor(activityId: string, viewerId: string | null): { count: number
return { count, hearted };
}
-function ownerAttribution(ownerId: string): { display: string; username: string | null } {
+/**
+ * Build the public-facing attribution for an owner. Prefer the user's chosen
+ * `display_name`; fall back to their `username` slug if set (also user-chosen);
+ * otherwise return null so the client hides attribution entirely. We
+ * deliberately do NOT fall back to the email or any prefix of it — that's a
+ * contact identifier the user didn't elect to surface.
+ *
+ * `username` (the link target) is returned independently and is only non-null
+ * when the owner has opted into a public list — drives whether the
+ * attribution renders as a link to //list.
+ */
+function ownerAttribution(ownerId: string): { display: string | null; username: string | null } {
const row = getDb()
- .prepare('SELECT display_name, email, username, public_list_enabled FROM users WHERE id = ?')
+ .prepare('SELECT display_name, username, public_list_enabled FROM users WHERE id = ?')
.get(ownerId) as
- | { display_name: string | null; email: string; username: string | null; public_list_enabled: number | null }
+ | { display_name: string | null; username: string | null; public_list_enabled: number | null }
| null;
- if (!row) return { display: 'ukjent', username: null };
+ if (!row) return { display: null, username: null };
const display = (row.display_name && row.display_name.trim())
? row.display_name
- : (row.email.indexOf('@') > 0 ? row.email.slice(0, row.email.indexOf('@')) : row.email);
+ : (row.username && row.username.trim())
+ ? row.username
+ : null;
const username = row.public_list_enabled === 1 ? row.username : null;
return { display, username };
}
diff --git a/server/users.ts b/server/users.ts
index d2f8e2b..0e31cf0 100644
--- a/server/users.ts
+++ b/server/users.ts
@@ -57,7 +57,9 @@ usersRoutes.get('/:username/list', (c) => {
id: r.id,
visibility: 'public',
owner_id: r.owner_id,
- owner_display: user.display_name?.trim() || username,
+ // Prefer the display name; fall back to the username slug (which is
+ // what the URL already shows). Never falls through to email/id.
+ owner_display: (user.display_name && user.display_name.trim()) || username,
// The list itself is at //list, so we already know the slug.
// Surfacing it on each row keeps ActivityRow's rendering uniform.
owner_username: username,
diff --git a/shared/types.ts b/shared/types.ts
index bec887e..546b371 100644
--- a/shared/types.ts
+++ b/shared/types.ts
@@ -173,7 +173,13 @@ export interface ActivityPublic {
id: string;
visibility: 'public';
owner_id: string; // serialized for public
- owner_display: string; // display_name OR derived handle (email prefix)
+ /**
+ * Public-facing handle: display_name OR (when only the slug is set) the
+ * username. NULL when the owner has set neither — in that case the client
+ * hides attribution entirely rather than falling back to the email or to
+ * an identifier the user didn't choose.
+ */
+ owner_display: string | null;
// Owner's URL slug, if they've opted into a public list. When non-null, the
// client renders the owner attribution as a link to //list.
owner_username: string | null;