Make Resend from-address config-only; drop credential status rows

The Settings page no longer renders the Resend From Address input or any
of the read-only "Set in config.toml" credential status rows (Apify key,
eBay id/secret, ntfy auth, Resend key). Those rows looked like editable
inputs but were dead text, and duplicated what the Test buttons verify
more authoritatively.

- resend_from is now sourced only from config.toml ([resend] from); it is
  removed from settingsKeys, the test-Resend handler, the scheduler email
  client, and the schema seed.
- Removed the credStatus templ component, the CredentialStatus field on
  SettingsData, and the credentialStatus() handler helper.
This commit is contained in:
prosolis
2026-06-20 15:42:14 -07:00
parent 72f4bdd88a
commit 56fe8d7c88
6 changed files with 307 additions and 482 deletions

View File

@@ -43,9 +43,9 @@ func (c AuthConfig) ForwardAuthEnabled() bool {
return strings.EqualFold(strings.TrimSpace(c.Mode), "forward")
}
// ResendConfig holds Resend transactional-email credentials. APIKey and From
// can both be overridden at runtime via /settings (resend_api_key,
// resend_from). From is an RFC-5322 address, e.g. "Veola <veola@example.com>".
// ResendConfig holds Resend transactional-email credentials, set only in
// config.toml (never via the web UI). From is an RFC-5322 address, e.g.
// "Veola <veola@example.com>".
type ResendConfig struct {
APIKey string `toml:"api_key"`
From string `toml:"from"`

View File

@@ -116,8 +116,7 @@ INSERT OR IGNORE INTO settings (key, value) VALUES
('match_confidence_threshold', '0.6'),
('apify_cost_per_call', '0.00'),
('monthly_budget_usd', '0.00'),
('resend_api_key', ''),
('resend_from', '');
('resend_api_key', '');
-- apify_api_usage tracks Apify actor runs per UTC day so the operator (and
-- every signed-in user) can see consumption and an estimated spend. Apify

View File

@@ -19,8 +19,7 @@ import (
// settingsKeys are the non-secret operational settings editable from the
// Settings page. API credentials (Apify, eBay, ntfy, Resend) are deliberately
// NOT here — they are managed only in config.toml on the server, so the UI
// never reads or writes them. credentialStatus surfaces whether each is
// configured, and the Test buttons verify them.
// never reads or writes them. The Test buttons verify them.
var settingsKeys = []string{
"ebay_daily_call_limit",
"ntfy_base_url",
@@ -29,29 +28,6 @@ var settingsKeys = []string{
"match_confidence_threshold",
"apify_cost_per_call",
"monthly_budget_usd",
"resend_from",
}
// credentialStatus reports, per credential, whether it is configured in
// config.toml — without exposing the secret itself. ntfy_auth reflects the
// Basic-auth user/password pair.
func (a *App) credentialStatus() map[string]string {
configured := map[string]bool{
"apify_api_key": strings.TrimSpace(a.Cfg.Apify.APIKey) != "",
"ebay_client_id": strings.TrimSpace(a.Cfg.Ebay.ClientID) != "",
"ebay_client_secret": strings.TrimSpace(a.Cfg.Ebay.ClientSecret) != "",
"ntfy_auth": strings.TrimSpace(a.Cfg.Ntfy.Username) != "" && a.Cfg.Ntfy.Password != "",
"resend_api_key": strings.TrimSpace(a.Cfg.Resend.APIKey) != "",
}
status := make(map[string]string, len(configured))
for k, ok := range configured {
if ok {
status[k] = "Set in config.toml"
} else {
status[k] = "Not set"
}
}
return status
}
func (a *App) settingsData(r *http.Request) (templates.SettingsData, error) {
@@ -69,7 +45,6 @@ func (a *App) settingsData(r *http.Request) (templates.SettingsData, error) {
return templates.SettingsData{
Page: a.page(r, "Settings", "settings"),
Values: values,
CredentialStatus: a.credentialStatus(),
IsAdmin: cur != nil && cur.Role == models.RoleAdmin,
Users: users,
EbayUsedToday: ebayUsed,
@@ -150,10 +125,7 @@ func (a *App) PostTestResend(w http.ResponseWriter, r *http.Request) {
if apiKey == "" {
apiKey = a.Cfg.Resend.APIKey
}
from := strings.TrimSpace(d.Values["resend_from"])
if from == "" {
from = a.Cfg.Resend.From
}
from := a.Cfg.Resend.From
to := ""
if cur != nil {
to = cur.Email

View File

@@ -21,11 +21,7 @@ func (s *Scheduler) emailClient(ctx context.Context) *email.Client {
if v, _ := s.store.GetSetting(ctx, "resend_api_key"); v != "" {
apiKey = v
}
from := s.cfg.Resend.From
if v, _ := s.store.GetSetting(ctx, "resend_from"); v != "" {
from = v
}
return email.New(apiKey, from)
return email.New(apiKey, s.cfg.Resend.From)
}
// dealMailer resolves the item owner and Resend client for deal-alert email.