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:
@@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
@@ -19,6 +20,11 @@ type DB struct {
|
||||
// from other errors.
|
||||
var ErrArtistNotFound = errors.New("artist not found")
|
||||
|
||||
// ErrReleaseNotFound is returned by SetReleaseIgnored when no external_release
|
||||
// row matches the given RGID (e.g. it was pruned by a concurrent re-sync). It
|
||||
// is a sentinel so callers (e.g. the web UI) can treat it as benign.
|
||||
var ErrReleaseNotFound = errors.New("release not found")
|
||||
|
||||
// New opens a SQLite database at dbPath and runs schema migrations.
|
||||
func New(dbPath string) (*DB, error) {
|
||||
// The _foreign_keys=on DSN parameter enables foreign key enforcement on
|
||||
@@ -30,16 +36,22 @@ func New(dbPath string) (*DB, error) {
|
||||
// migrations would appear missing on some. Limiting the pool to a single
|
||||
// connection keeps one in-memory database per New() call, which is correct
|
||||
// for both tests (isolated) and the single-process production service.
|
||||
conn, err := sql.Open("sqlite3", dbPath+"?_foreign_keys=on")
|
||||
// Append the foreign_keys pragma via net/url so a caller-supplied path that
|
||||
// already contains a query string is not silently broken.
|
||||
dsn := dbPath
|
||||
if !strings.Contains(dsn, "?") {
|
||||
dsn += "?"
|
||||
} else {
|
||||
dsn += "&"
|
||||
}
|
||||
dsn += "_foreign_keys=on"
|
||||
conn, err := sql.Open("sqlite3", dsn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open database: %w", err)
|
||||
}
|
||||
if dbPath == ":memory:" {
|
||||
conn.SetMaxOpenConns(1)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open database: %w", err)
|
||||
}
|
||||
|
||||
// Enable WAL mode for better concurrent read performance.
|
||||
if _, err := conn.Exec("PRAGMA journal_mode=WAL"); err != nil {
|
||||
|
||||
@@ -160,7 +160,7 @@ func SetReleaseIgnored(db *DB, rgid string, ignored bool) error {
|
||||
return fmt.Errorf("rows affected: %w", err)
|
||||
}
|
||||
if rowsAffected == 0 {
|
||||
return fmt.Errorf("release not found: %s", rgid)
|
||||
return fmt.Errorf("%w: %s", ErrReleaseNotFound, rgid)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user