feat: add notes field to favorites and enhance OG meta tags

Add an optional long-form "notes" text field to each favorite for
reviews, thoughts, or extended descriptions. The field is stored in
SQLite via a new migration (002_add_fave_notes.sql) and propagated
through the entire stack:

- Model: Notes field on Fave struct
- Store: All SQL queries (Create, GetByID, Update, list methods,
  scanFaves) updated with notes column
- Web handlers: Read/write notes in create, edit, update forms
- API handlers: Notes in create, update, get, import request/response
- Export: Notes included in both JSON and CSV exports
- Import: Notes parsed from both JSON and CSV imports
- Feed: Notes used as Atom feed item summary when present
- Form template: New textarea between URL and image fields
- Detail template: Display notes, enhanced og:description with
  cascade: notes (truncated) → URL → generic fallback text

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-04-04 00:40:08 +02:00
commit 485d01ce45
14 changed files with 151 additions and 71 deletions

View file

@ -135,6 +135,7 @@ func (h *Handler) handleCreateFave(w http.ResponseWriter, r *http.Request) {
var req struct {
Description string `json:"description"`
URL string `json:"url"`
Notes string `json:"notes"`
Privacy string `json:"privacy"`
Tags []string `json:"tags"`
}
@ -151,7 +152,7 @@ func (h *Handler) handleCreateFave(w http.ResponseWriter, r *http.Request) {
req.Privacy = user.DefaultFavePrivacy
}
fave, err := h.deps.Faves.Create(user.ID, req.Description, req.URL, "", req.Privacy)
fave, err := h.deps.Faves.Create(user.ID, req.Description, req.URL, "", req.Notes, req.Privacy)
if err != nil {
slog.Error("api: create fave error", "error", err)
jsonError(w, "Internal error", http.StatusInternalServerError)
@ -222,6 +223,7 @@ func (h *Handler) handleUpdateFave(w http.ResponseWriter, r *http.Request) {
var req struct {
Description string `json:"description"`
URL string `json:"url"`
Notes string `json:"notes"`
Privacy string `json:"privacy"`
Tags []string `json:"tags"`
}
@ -237,7 +239,7 @@ func (h *Handler) handleUpdateFave(w http.ResponseWriter, r *http.Request) {
req.Privacy = fave.Privacy
}
if err := h.deps.Faves.Update(id, req.Description, req.URL, fave.ImagePath, req.Privacy); err != nil {
if err := h.deps.Faves.Update(id, req.Description, req.URL, fave.ImagePath, req.Notes, req.Privacy); err != nil {
slog.Error("api: update fave error", "error", err)
jsonError(w, "Internal error", http.StatusInternalServerError)
return
@ -378,6 +380,7 @@ func (h *Handler) handleImport(w http.ResponseWriter, r *http.Request) {
var faves []struct {
Description string `json:"description"`
URL string `json:"url"`
Notes string `json:"notes"`
Privacy string `json:"privacy"`
Tags []string `json:"tags"`
}
@ -395,7 +398,7 @@ func (h *Handler) handleImport(w http.ResponseWriter, r *http.Request) {
if privacy != "public" && privacy != "private" {
privacy = user.DefaultFavePrivacy
}
fave, err := h.deps.Faves.Create(user.ID, f.Description, f.URL, "", privacy)
fave, err := h.deps.Faves.Create(user.ID, f.Description, f.URL, "", f.Notes, privacy)
if err != nil {
continue
}
@ -446,6 +449,7 @@ func faveJSON(f *model.Fave) map[string]any {
"id": f.ID,
"description": f.Description,
"url": f.URL,
"notes": f.Notes,
"image_path": f.ImagePath,
"privacy": f.Privacy,
"tags": tags,

View file

@ -222,7 +222,7 @@ func TestAPIGetFave(t *testing.T) {
// Create a public fave directly.
user, _ := users.GetByUsername("testuser")
fave, _ := h.deps.Faves.Create(user.ID, "Test fave", "https://example.com", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Test fave", "https://example.com", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"test"})
req := httptest.NewRequest("GET", "/api/v1/faves/"+faveIDStr(fave.ID), nil)
@ -257,7 +257,7 @@ func TestAPIPrivateFaveHiddenFromOthers(t *testing.T) {
// User A creates a private fave.
userA, _ := users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "Secret", "", "", "private")
fave, _ := h.deps.Faves.Create(userA.ID, "Secret", "", "", "", "private")
// User B tries to access it.
cookieB := apiLogin(t, users, sessions, "userb", "pass123", "user")
@ -276,7 +276,7 @@ func TestAPIPrivateFaveVisibleToOwner(t *testing.T) {
h, mux, users, sessions := testAPIServer(t)
userA, _ := users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "My secret", "", "", "private")
fave, _ := h.deps.Faves.Create(userA.ID, "My secret", "", "", "", "private")
tokenA, _ := sessions.Create(userA.ID)
cookieA := &http.Cookie{Name: "session", Value: tokenA}
@ -295,7 +295,7 @@ func TestAPIUpdateFave(t *testing.T) {
h, mux, users, sessions := testAPIServer(t)
user, _ := users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Original", "https://old.com", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Original", "https://old.com", "", "", "public")
token, _ := sessions.Create(user.ID)
cookie := &http.Cookie{Name: "session", Value: token}
@ -322,7 +322,7 @@ func TestAPIUpdateFaveNotOwner(t *testing.T) {
h, mux, users, sessions := testAPIServer(t)
userA, _ := users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "public")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "", "public")
cookieB := apiLogin(t, users, sessions, "userb", "pass123", "user")
@ -341,7 +341,7 @@ func TestAPIDeleteFave(t *testing.T) {
h, mux, users, sessions := testAPIServer(t)
user, _ := users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Delete me", "", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Delete me", "", "", "", "public")
token, _ := sessions.Create(user.ID)
cookie := &http.Cookie{Name: "session", Value: token}
@ -368,7 +368,7 @@ func TestAPIDeleteFaveNotOwner(t *testing.T) {
h, mux, users, sessions := testAPIServer(t)
userA, _ := users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "public")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "", "public")
cookieB := apiLogin(t, users, sessions, "userb", "pass123", "user")
@ -386,9 +386,9 @@ func TestAPIListFaves(t *testing.T) {
h, mux, users, sessions := testAPIServer(t)
user, _ := users.Create("testuser", "pass123", "user")
h.deps.Faves.Create(user.ID, "Fave 1", "", "", "public")
h.deps.Faves.Create(user.ID, "Fave 2", "", "", "public")
h.deps.Faves.Create(user.ID, "Fave 3", "", "", "private")
h.deps.Faves.Create(user.ID, "Fave 1", "", "", "", "public")
h.deps.Faves.Create(user.ID, "Fave 2", "", "", "", "public")
h.deps.Faves.Create(user.ID, "Fave 3", "", "", "", "private")
token, _ := sessions.Create(user.ID)
cookie := &http.Cookie{Name: "session", Value: token}
@ -413,7 +413,7 @@ func TestAPIListFavesPagination(t *testing.T) {
user, _ := users.Create("testuser", "pass123", "user")
for i := 0; i < 5; i++ {
h.deps.Faves.Create(user.ID, "Fave", "", "", "public")
h.deps.Faves.Create(user.ID, "Fave", "", "", "", "public")
}
token, _ := sessions.Create(user.ID)
cookie := &http.Cookie{Name: "session", Value: token}
@ -443,7 +443,7 @@ func TestAPISearchTags(t *testing.T) {
h, mux, users, _ := testAPIServer(t)
user, _ := users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Test", "", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Test", "", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"golang", "goroutines", "python"})
req := httptest.NewRequest("GET", "/api/v1/tags?q=go", nil)
@ -531,8 +531,8 @@ func TestAPIGetDisabledUser(t *testing.T) {
func TestAPIGetUserFaves(t *testing.T) {
h, mux, users, _ := testAPIServer(t)
user, _ := users.Create("testuser", "pass123", "user")
h.deps.Faves.Create(user.ID, "Public fave", "", "", "public")
h.deps.Faves.Create(user.ID, "Private fave", "", "", "private")
h.deps.Faves.Create(user.ID, "Public fave", "", "", "", "public")
h.deps.Faves.Create(user.ID, "Private fave", "", "", "", "private")
req := httptest.NewRequest("GET", "/api/v1/users/testuser/faves", nil)
rr := httptest.NewRecorder()
@ -555,8 +555,8 @@ func TestAPIExport(t *testing.T) {
h, mux, users, sessions := testAPIServer(t)
user, _ := users.Create("testuser", "pass123", "user")
h.deps.Faves.Create(user.ID, "Fave 1", "", "", "public")
h.deps.Faves.Create(user.ID, "Fave 2", "", "", "private")
h.deps.Faves.Create(user.ID, "Fave 1", "", "", "", "public")
h.deps.Faves.Create(user.ID, "Fave 2", "", "", "", "private")
token, _ := sessions.Create(user.ID)
cookie := &http.Cookie{Name: "session", Value: token}

View file

@ -72,12 +72,13 @@ func (h *Handler) handleFaveCreate(w http.ResponseWriter, r *http.Request) {
description := strings.TrimSpace(r.FormValue("description"))
url := strings.TrimSpace(r.FormValue("url"))
notes := strings.TrimSpace(r.FormValue("notes"))
privacy := r.FormValue("privacy")
tagStr := r.FormValue("tags")
if description == "" {
h.flash(w, r, "fave_form", "Beskrivelse er påkrevd.", "error", map[string]any{
"IsNew": true, "Description": description, "URL": url, "Tags": tagStr, "Privacy": privacy,
"IsNew": true, "Description": description, "URL": url, "Notes": notes, "Tags": tagStr, "Privacy": privacy,
})
return
}
@ -95,7 +96,7 @@ func (h *Handler) handleFaveCreate(w http.ResponseWriter, r *http.Request) {
if err != nil {
slog.Error("image process error", "error", err)
h.flash(w, r, "fave_form", "Kunne ikke behandle bildet. Sjekk at filen er et gyldig bilde (JPEG, PNG, GIF eller WebP).", "error", map[string]any{
"IsNew": true, "Description": description, "URL": url, "Tags": tagStr, "Privacy": privacy,
"IsNew": true, "Description": description, "URL": url, "Notes": notes, "Tags": tagStr, "Privacy": privacy,
})
return
}
@ -103,7 +104,7 @@ func (h *Handler) handleFaveCreate(w http.ResponseWriter, r *http.Request) {
}
// Create the fave.
fave, err := h.deps.Faves.Create(user.ID, description, url, imagePath, privacy)
fave, err := h.deps.Faves.Create(user.ID, description, url, imagePath, notes, privacy)
if err != nil {
slog.Error("create fave error", "error", err)
h.flash(w, r, "fave_form", "Noe gikk galt. Prøv igjen.", "error", map[string]any{"IsNew": true})
@ -205,6 +206,7 @@ func (h *Handler) handleFaveEdit(w http.ResponseWriter, r *http.Request) {
"Fave": fave,
"Description": fave.Description,
"URL": fave.URL,
"Notes": fave.Notes,
"Privacy": fave.Privacy,
"Tags": strings.Join(tagNames, ", "),
},
@ -244,6 +246,7 @@ func (h *Handler) handleFaveUpdate(w http.ResponseWriter, r *http.Request) {
description := strings.TrimSpace(r.FormValue("description"))
url := strings.TrimSpace(r.FormValue("url"))
notes := strings.TrimSpace(r.FormValue("notes"))
privacy := r.FormValue("privacy")
tagStr := r.FormValue("tags")
@ -283,7 +286,7 @@ func (h *Handler) handleFaveUpdate(w http.ResponseWriter, r *http.Request) {
imagePath = ""
}
if err := h.deps.Faves.Update(id, description, url, imagePath, privacy); err != nil {
if err := h.deps.Faves.Update(id, description, url, imagePath, notes, privacy); err != nil {
slog.Error("update fave error", "error", err)
h.flash(w, r, "fave_form", "Noe gikk galt. Prøv igjen.", "error", map[string]any{"IsNew": false, "Fave": fave})
return

View file

@ -129,6 +129,10 @@ func favesToFeedItems(faves []*model.Fave, baseURL string) []*feeds.Item {
Updated: f.UpdatedAt,
}
if f.Notes != "" {
item.Description = f.Notes
}
if f.URL != "" {
escaped := html.EscapeString(f.URL)
item.Content = `<p><a href="` + escaped + `">` + escaped + `</a></p>`

View file

@ -220,7 +220,7 @@ func TestPrivateFaveHiddenFromOthers(t *testing.T) {
// User A creates a private fave.
userA, _ := h.deps.Users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "Secret fave", "", "", "private")
fave, _ := h.deps.Faves.Create(userA.ID, "Secret fave", "", "", "", "private")
// User B tries to view it.
cookieB := loginUser(t, h, "userb", "pass123", "user")
@ -239,7 +239,7 @@ func TestPrivateFaveVisibleToOwner(t *testing.T) {
h, mux := testServer(t)
userA, _ := h.deps.Users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "My secret", "", "", "private")
fave, _ := h.deps.Faves.Create(userA.ID, "My secret", "", "", "", "private")
tokenA, _ := h.deps.Sessions.Create(userA.ID)
cookieA := &http.Cookie{Name: "session", Value: tokenA}
@ -290,7 +290,7 @@ func TestTagSearchEndpoint(t *testing.T) {
// Create some tags via faves.
user, _ := h.deps.Users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Test", "", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Test", "", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"music", "movies", "manga"})
req := httptest.NewRequest("GET", "/tags/search?q=mu", nil)
@ -310,7 +310,7 @@ func TestFeedGlobal(t *testing.T) {
h, mux := testServer(t)
user, _ := h.deps.Users.Create("testuser", "pass123", "user")
h.deps.Faves.Create(user.ID, "Public fave", "", "", "public")
h.deps.Faves.Create(user.ID, "Public fave", "", "", "", "public")
req := httptest.NewRequest("GET", "/feed.xml", nil)
rr := httptest.NewRecorder()

View file

@ -21,6 +21,7 @@ const maxExportFaves = 100000
type ExportFave struct {
Description string `json:"description"`
URL string `json:"url,omitempty"`
Notes string `json:"notes,omitempty"`
Privacy string `json:"privacy"`
Tags []string `json:"tags,omitempty"`
CreatedAt string `json:"created_at"`
@ -57,6 +58,7 @@ func (h *Handler) handleExportJSON(w http.ResponseWriter, r *http.Request) {
export[i] = ExportFave{
Description: f.Description,
URL: f.URL,
Notes: f.Notes,
Privacy: f.Privacy,
Tags: tags,
CreatedAt: f.CreatedAt.Format("2006-01-02T15:04:05Z"),
@ -89,7 +91,7 @@ func (h *Handler) handleExportCSV(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", "attachment; filename=favoritter.csv")
cw := csv.NewWriter(w)
cw.Write([]string{"description", "url", "privacy", "tags", "created_at"})
cw.Write([]string{"description", "url", "notes", "privacy", "tags", "created_at"})
for _, f := range faves {
tags := make([]string, len(f.Tags))
@ -99,6 +101,7 @@ func (h *Handler) handleExportCSV(w http.ResponseWriter, r *http.Request) {
cw.Write([]string{
f.Description,
f.URL,
f.Notes,
f.Privacy,
strings.Join(tags, ","),
f.CreatedAt.Format("2006-01-02T15:04:05Z"),
@ -159,7 +162,7 @@ func (h *Handler) handleImportPost(w http.ResponseWriter, r *http.Request) {
privacy = user.DefaultFavePrivacy
}
fave, err := h.deps.Faves.Create(user.ID, ef.Description, ef.URL, "", privacy)
fave, err := h.deps.Faves.Create(user.ID, ef.Description, ef.URL, "", ef.Notes, privacy)
if err != nil {
slog.Error("import: create fave error", "error", err)
continue
@ -213,6 +216,9 @@ func parseImportCSV(r io.Reader) ([]ExportFave, error) {
if idx, ok := colMap["url"]; ok && idx < len(row) {
f.URL = row[idx]
}
if idx, ok := colMap["notes"]; ok && idx < len(row) {
f.Notes = row[idx]
}
if idx, ok := colMap["privacy"]; ok && idx < len(row) {
f.Privacy = row[idx]
}

View file

@ -364,7 +364,7 @@ func TestEditFaveNotOwner(t *testing.T) {
h, mux := testServer(t)
userA, _ := h.deps.Users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "public")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "", "public")
cookieB := loginUser(t, h, "userb", "pass123", "user")
@ -382,7 +382,7 @@ func TestDeleteFaveHTMX(t *testing.T) {
h, mux := testServer(t)
user, _ := h.deps.Users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Delete me", "", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Delete me", "", "", "", "public")
token, _ := h.deps.Sessions.Create(user.ID)
cookie := &http.Cookie{Name: "session", Value: token}
@ -409,7 +409,7 @@ func TestDeleteFaveNotOwner(t *testing.T) {
h, mux := testServer(t)
userA, _ := h.deps.Users.Create("usera", "pass123", "user")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "public")
fave, _ := h.deps.Faves.Create(userA.ID, "A's fave", "", "", "", "public")
cookieB := loginUser(t, h, "userb", "pass123", "user")
@ -623,7 +623,7 @@ func TestAdminTags(t *testing.T) {
// Create a tag via a fave.
admin, _ := h.deps.Users.GetByUsername("admin")
fave, _ := h.deps.Faves.Create(admin.ID, "Test", "", "", "public")
fave, _ := h.deps.Faves.Create(admin.ID, "Test", "", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"testmerke"})
req := httptest.NewRequest("GET", "/admin/tags", nil)
@ -646,7 +646,7 @@ func TestUserFeed(t *testing.T) {
user, _ := h.deps.Users.Create("feeduser", "pass123", "user")
h.deps.Users.UpdateProfile(user.ID, "Feed User", "", "public", "public")
h.deps.Faves.Create(user.ID, "User fave", "", "", "public")
h.deps.Faves.Create(user.ID, "User fave", "", "", "", "public")
req := httptest.NewRequest("GET", "/u/feeduser/feed.xml", nil)
rr := httptest.NewRecorder()
@ -668,8 +668,8 @@ func TestFeedExcludesPrivate(t *testing.T) {
h, mux := testServer(t)
user, _ := h.deps.Users.Create("testuser", "pass123", "user")
h.deps.Faves.Create(user.ID, "Public fave", "", "", "public")
h.deps.Faves.Create(user.ID, "Secret fave", "", "", "private")
h.deps.Faves.Create(user.ID, "Public fave", "", "", "", "public")
h.deps.Faves.Create(user.ID, "Secret fave", "", "", "", "private")
req := httptest.NewRequest("GET", "/feed.xml", nil)
rr := httptest.NewRecorder()
@ -688,7 +688,7 @@ func TestTagFeed(t *testing.T) {
h, mux := testServer(t)
user, _ := h.deps.Users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Tagged fave", "", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Tagged fave", "", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"golang"})
req := httptest.NewRequest("GET", "/tags/golang/feed.xml", nil)
@ -725,7 +725,7 @@ func TestExportJSON(t *testing.T) {
cookie := loginUser(t, h, "testuser", "pass123", "user")
user, _ := h.deps.Users.GetByUsername("testuser")
fave, _ := h.deps.Faves.Create(user.ID, "Export me", "https://example.com", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Export me", "https://example.com", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"test"})
req := httptest.NewRequest("GET", "/export/json", nil)
@ -759,7 +759,7 @@ func TestExportCSV(t *testing.T) {
cookie := loginUser(t, h, "testuser", "pass123", "user")
user, _ := h.deps.Users.GetByUsername("testuser")
h.deps.Faves.Create(user.ID, "CSV fave", "", "", "public")
h.deps.Faves.Create(user.ID, "CSV fave", "", "", "", "public")
req := httptest.NewRequest("GET", "/export/csv", nil)
req.AddCookie(cookie)
@ -871,7 +871,7 @@ func TestProfileOwnerSeesPrivateFaves(t *testing.T) {
h, mux := testServer(t)
user, _ := h.deps.Users.Create("owner", "pass123", "user")
h.deps.Faves.Create(user.ID, "Private fave", "", "", "private")
h.deps.Faves.Create(user.ID, "Private fave", "", "", "", "private")
token, _ := h.deps.Sessions.Create(user.ID)
cookie := &http.Cookie{Name: "session", Value: token}
@ -893,8 +893,8 @@ func TestProfileVisitorCannotSeePrivateFaves(t *testing.T) {
user, _ := h.deps.Users.Create("owner", "pass123", "user")
h.deps.Users.UpdateProfile(user.ID, "Owner", "", "public", "public")
h.deps.Faves.Create(user.ID, "Only public", "", "", "public")
h.deps.Faves.Create(user.ID, "Hidden secret", "", "", "private")
h.deps.Faves.Create(user.ID, "Only public", "", "", "", "public")
h.deps.Faves.Create(user.ID, "Hidden secret", "", "", "", "private")
req := httptest.NewRequest("GET", "/u/owner", nil)
rr := httptest.NewRecorder()
@ -915,7 +915,7 @@ func TestTagBrowse(t *testing.T) {
h, mux := testServer(t)
user, _ := h.deps.Users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Tagged", "", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Tagged", "", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"golang"})
req := httptest.NewRequest("GET", "/tags/golang", nil)
@ -949,7 +949,7 @@ func TestHomePageAuthenticated(t *testing.T) {
cookie := loginUser(t, h, "testuser", "pass123", "user")
user, _ := h.deps.Users.GetByUsername("testuser")
h.deps.Faves.Create(user.ID, "Home fave", "", "", "public")
h.deps.Faves.Create(user.ID, "Home fave", "", "", "", "public")
req := httptest.NewRequest("GET", "/", nil)
req.AddCookie(cookie)
@ -1074,7 +1074,7 @@ func TestTagSuggestionsNoInlineHandlers(t *testing.T) {
h, mux := testServer(t)
user, _ := h.deps.Users.Create("testuser", "pass123", "user")
fave, _ := h.deps.Faves.Create(user.ID, "Test", "", "", "public")
fave, _ := h.deps.Faves.Create(user.ID, "Test", "", "", "", "public")
h.deps.Tags.SetFaveTags(fave.ID, []string{"golang", "goroutines"})
req := httptest.NewRequest("GET", "/tags/search?q=go", nil)
@ -1117,7 +1117,7 @@ func TestDisplayNameFallbackToUsername(t *testing.T) {
// Create a user WITHOUT a display name and a public fave.
user, _ := h.deps.Users.GetByUsername("testuser")
h.deps.Faves.Create(user.ID, "Test fave", "", "", "public")
h.deps.Faves.Create(user.ID, "Test fave", "", "", "", "public")
// The home page shows "av <display_name>" — with no display name set,
// it should fall back to the username.