fix: address code review findings

- notifier: show artist display names (not internal IDs) in digest; resolve
  names from artist_settings and fall back to ID when unavailable
- notifier: skip sending an empty digest to avoid daily spam
- config: require telegram token/chat_id when enabled
- web: warn loudly when auth is disabled on a non-loopback bind; add HTTP
  server timeouts
- web: treat SetReleaseIgnored "release not found" as benign redirect (0 rows)
- musicbrainz: reject low-score/name-mismatched MBID resolutions instead of
  silently caching the wrong artist
- database: remove dead duplicate err check; harden DSN param appending
- musicbrainz: check rows.Err() after iterating existing releases
This commit is contained in:
2026-07-19 23:46:05 +03:00
parent 389d177d85
commit 7cdb473d9c
12 changed files with 189 additions and 22 deletions

View File

@@ -26,7 +26,7 @@ func (s *stubSender) Send(ctx context.Context, message string) error {
}
func TestFormatDigest_Empty(t *testing.T) {
got := FormatDigest(nil, "http://ui")
got := FormatDigest(nil, "http://ui", nil)
if got != "NaviWatcher: no new missing releases found." {
t.Fatalf("unexpected empty digest: %q", got)
}
@@ -38,7 +38,7 @@ func TestFormatDigest_GroupsByArtistAndCounts(t *testing.T) {
{ArtistID: "art-a", Title: "Alpha", RGID: "r1"},
{ArtistID: "art-a", Title: "Beta", RGID: "r2"},
}
got := FormatDigest(missing, "http://localhost:8080/")
got := FormatDigest(missing, "http://localhost:8080/", nil)
if !strings.Contains(got, "art-a (2):") {
t.Errorf("expected art-a with count 2, got:\n%s", got)
}
@@ -60,9 +60,45 @@ func TestFormatDigest_GroupsByArtistAndCounts(t *testing.T) {
}
}
func TestFormatDigest_UsesArtistNameWhenProvided(t *testing.T) {
missing := []scanner.MissingRelease{
{ArtistID: "art-2", Title: "Zebra", RGID: "r3"},
{ArtistID: "art-1", Title: "Alpha", RGID: "r1"},
{ArtistID: "art-1", Title: "Beta", RGID: "r2"},
}
names := map[string]string{"art-1": "Alpha Artist", "art-2": "Zebra Artist"}
got := FormatDigest(missing, "", names)
// Display names are used as labels and sorted alphabetically by name.
if !strings.Contains(got, "Alpha Artist (2):") {
t.Errorf("expected name label with count 2, got:\n%s", got)
}
if !strings.Contains(got, "Zebra Artist (1):") {
t.Errorf("expected name label with count 1, got:\n%s", got)
}
if strings.Index(got, "Alpha Artist") > strings.Index(got, "Zebra Artist") {
t.Errorf("artists not sorted by name: got:\n%s", got)
}
}
func TestFormatDigest_FallsBackToIDWhenNameMissing(t *testing.T) {
missing := []scanner.MissingRelease{
{ArtistID: "art-1", Title: "Alpha", RGID: "r1"},
{ArtistID: "art-2", Title: "Beta", RGID: "r2"},
}
// Name map present but does not cover art-2 -> falls back to ID.
names := map[string]string{"art-1": "Named Artist"}
got := FormatDigest(missing, "", names)
if !strings.Contains(got, "Named Artist (1):") {
t.Errorf("expected named artist label, got:\n%s", got)
}
if !strings.Contains(got, "art-2 (1):") {
t.Errorf("expected ID fallback for art-2, got:\n%s", got)
}
}
func TestFormatDigest_EmptyUIBaseURLOmitsLink(t *testing.T) {
missing := []scanner.MissingRelease{{ArtistID: "a", Title: "x", RGID: "r1"}}
got := FormatDigest(missing, "")
got := FormatDigest(missing, "", nil)
if strings.Contains(got, "View details:") {
t.Errorf("did not expect UI link when base URL empty: got:\n%s", got)
}