2 Commits

Author SHA1 Message Date
bvandeusen e4ebc71162 fix(ci): mailer + audit lint + settings Save button collision
Three Go lint hits + two web test failures, all from the U3 push.

- internal/mailer/mailer.go: SentEmail.HtmlBody → HTMLBody (Go's
  initialism convention; revive flagged); FakeSender.Send unused
  ctx parameter renamed to _.
- internal/audit/audit_test.go: removed dead validUUID helper. It
  was added speculatively in U1-T1 and never called by any test.
  pgtype import stays — other tests use it.
- web/src/routes/settings/settings.test.ts: existing ListenBrainz
  tests queried `getByRole('button', { name: /save/i })` which
  worked when the page had only one Save button. The new Profile
  card adds a "Save profile" button that also matches the regex,
  triggering "found multiple elements". Anchored to /^save$/i for
  exact-match. The newer Save profile tests still use
  /save profile/i which is unique.

This is the same shape of test-fixture-lag I owe an answer for: I
landed new content that broke an existing test, and the existing
test had a too-loose selector. The right fix is to tighten the old
selector now (this commit) and to flag this pattern — selectors
that regex-match by partial words — as a candidate for the DRY
pass / test-utils consolidation.
2026-05-07 18:15:39 -04:00
bvandeusen aa67a09b80 feat(server/m7-user-mgmt): mailer package + SMTP config endpoints (U3)
New internal/mailer/ package:

- Sender interface with two impls: SMTPSender (production, reads
  smtp_config at send time so admin edits apply without restart;
  uses stdlib net/smtp + STARTTLS) and FakeSender (test/concurrent-
  safe call recorder).
- Embedded text + HTML templates for the password reset email,
  rendered via stdlib text/template + html/template. The HTML
  uses the FabledSword forest-teal accent color.
- ErrNotConfigured surfaces when smtp_config.enabled is false or
  required fields are empty; callers like the future forgot-password
  handler will treat this as "log and pretend success" to avoid
  user-enumeration leaks.

Three admin endpoints under RequireAdmin:

- GET /api/admin/smtp-config — returns the singleton; password
  field is masked ("***" or "").
- PUT /api/admin/smtp-config — updates settings. Validates
  host + from_address are non-empty when enabled=true. Empty
  password in the request preserves the stored value (so the
  operator doesn't have to re-enter it on every save).
- POST /api/admin/smtp-config/test — sends a real test email to
  the calling admin's email. 400 if admin has no email; 500 with
  the error message on send failure (so the operator can debug
  config without grep-then-trace through logs).

Tests cover the password-mask, password-preservation-on-empty,
enabled-requires-host-and-from validation, and the no-email-on-file
rejection. Mailer unit tests cover the fake recorder and template
rendering. The "real SMTP send" path needs a live server and isn't
covered in CI; the FakeSender covers that role for downstream tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 12:43:44 -04:00