From d4f4012c8a812d4399835ffead72463c1f66f3f5 Mon Sep 17 00:00:00 2001 From: Tyler Koenig Date: Fri, 15 May 2026 00:37:20 -0400 Subject: [PATCH] refactor(store): add error returns to all Store interface methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every Store method now returns an error. Callers handle errors gracefully — TUI logs to event log, server returns HTTP 500, monitor engine logs and retries. All rows.Scan() errors are now checked in sqlstore.go instead of silently appending corrupt data. - GetSites, GetAllAlerts, GetAllUsers return ([]T, error) - GetAlert returns (AlertConfig, error) instead of (AlertConfig, bool) - AddSite, UpdateSite, DeleteSite, etc. all return error - SaveCheck, LoadAllHistory, ExportData return error - ~25 caller sites updated across tui, server, monitor, main --- cmd/goupkeep/main.go | 10 ++- internal/monitor/history.go | 8 +- internal/monitor/monitor.go | 11 ++- internal/server/server.go | 7 +- internal/store/sqlstore.go | 146 ++++++++++++++++++++++++------------ internal/store/store.go | 28 +++---- internal/tui/tab_alerts.go | 9 ++- internal/tui/tab_sites.go | 22 ++++-- internal/tui/tab_users.go | 9 ++- internal/tui/tui.go | 28 ++++--- 10 files changed, 185 insertions(+), 93 deletions(-) diff --git a/cmd/goupkeep/main.go b/cmd/goupkeep/main.go index cfd5c2f..77cdadd 100644 --- a/cmd/goupkeep/main.go +++ b/cmd/goupkeep/main.go @@ -174,7 +174,8 @@ func startSSHServer(port int) { } func seedDemoData(s store.Store) { - if existing := s.GetSites(); len(existing) > 0 { + existing, _ := s.GetSites() + if len(existing) > 0 { return } fmt.Println("Seeding demo data...") @@ -187,7 +188,7 @@ func seedDemoData(s store.Store) { "from": "oncall@example.com", "to": "team@example.com", }) - alerts := s.GetAllAlerts() + alerts, _ := s.GetAllAlerts() alertID := 0 if len(alerts) > 0 { alertID = alerts[0].ID @@ -206,7 +207,10 @@ func seedDemoData(s store.Store) { } func isKeyAllowed(incomingKey ssh.PublicKey) bool { - users := store.Get().GetAllUsers() + users, err := store.Get().GetAllUsers() + if err != nil { + return false + } for _, u := range users { allowedKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(u.PublicKey)) if err != nil { diff --git a/internal/monitor/history.go b/internal/monitor/history.go index 8642255..43ef0ee 100644 --- a/internal/monitor/history.go +++ b/internal/monitor/history.go @@ -25,7 +25,11 @@ func InitHistoryFromStore() { if s == nil { return } - all := s.LoadAllHistory(maxHistoryLen) + all, err := s.LoadAllHistory(maxHistoryLen) + if err != nil { + AddLog("Failed to load check history: " + err.Error()) + return + } historyMu.Lock() defer historyMu.Unlock() for siteID, records := range all { @@ -71,7 +75,7 @@ func RecordCheck(siteID int, latency time.Duration, isUp bool) { } if s := store.Get(); s != nil { - go s.SaveCheck(siteID, latency.Nanoseconds(), isUp) + go func() { _ = s.SaveCheck(siteID, latency.Nanoseconds(), isUp) }() } } diff --git a/internal/monitor/monitor.go b/internal/monitor/monitor.go index 3f2a869..27925ed 100644 --- a/internal/monitor/monitor.go +++ b/internal/monitor/monitor.go @@ -128,7 +128,12 @@ func StartEngine() { continue } - sites := s_instance.GetSites() + sites, err := s_instance.GetSites() + if err != nil { + AddLog(fmt.Sprintf("Failed to load sites: %v", err)) + time.Sleep(5 * time.Second) + continue + } for _, s := range sites { Mutex.RLock() _, exists := LiveState[s.ID] @@ -406,8 +411,8 @@ func triggerAlert(alertID int, title, message string) { if s_instance == nil { return } - cfg, ok := s_instance.GetAlert(alertID) - if !ok { + cfg, err := s_instance.GetAlert(alertID) + if err != nil { return } provider := alert.GetProvider(cfg) diff --git a/internal/server/server.go b/internal/server/server.go index 3cf6228..bb97a88 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -185,7 +185,12 @@ func Start(cfg ServerConfig) { http.Error(w, "Unauthorized: UPKEEP_CLUSTER_SECRET required", 401) return } - data := store.Get().ExportData() + data, err := store.Get().ExportData() + if err != nil { + log.Printf("Export failed: %v", err) + http.Error(w, "Export failed", 500) + return + } json.NewEncoder(w).Encode(data) }) diff --git a/internal/store/sqlstore.go b/internal/store/sqlstore.go index a715a02..3142399 100644 --- a/internal/store/sqlstore.go +++ b/internal/store/sqlstore.go @@ -48,7 +48,7 @@ func (s *SQLStore) Init() error { return nil } -func (s *SQLStore) GetSites() []models.Site { +func (s *SQLStore) GetSites() ([]models.Site, error) { bf := s.dialect.BoolFalse() query := fmt.Sprintf( "SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries, COALESCE(hostname, ''), COALESCE(port, 0), COALESCE(timeout, 0), COALESCE(method, 'GET'), COALESCE(description, ''), COALESCE(parent_id, 0), COALESCE(accepted_codes, '200-299'), COALESCE(dns_resolve_type, ''), COALESCE(dns_server, ''), COALESCE(ignore_tls, %s), COALESCE(paused, %s) FROM sites", @@ -56,107 +56,132 @@ func (s *SQLStore) GetSites() []models.Site { ) rows, err := s.db.Query(query) if err != nil { - return []models.Site{} + return nil, err } defer rows.Close() var sites []models.Site for rows.Next() { var st models.Site - rows.Scan(&st.ID, &st.Name, &st.URL, &st.Type, &st.Token, &st.Interval, &st.AlertID, + if err := rows.Scan(&st.ID, &st.Name, &st.URL, &st.Type, &st.Token, &st.Interval, &st.AlertID, &st.CheckSSL, &st.ExpiryThreshold, &st.MaxRetries, &st.Hostname, &st.Port, &st.Timeout, &st.Method, &st.Description, &st.ParentID, &st.AcceptedCodes, &st.DNSResolveType, - &st.DNSServer, &st.IgnoreTLS, &st.Paused) + &st.DNSServer, &st.IgnoreTLS, &st.Paused); err != nil { + return sites, err + } sites = append(sites, st) } - return sites + return sites, rows.Err() } -func (s *SQLStore) AddSite(site models.Site) { +func (s *SQLStore) AddSite(site models.Site) error { token := "" if site.Type == "push" { token = generateToken() } - s.db.Exec(s.q("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), + _, err := s.db.Exec(s.q("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), site.Name, site.URL, site.Type, token, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries, site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.Paused) + return err } -func (s *SQLStore) UpdateSite(site models.Site) { +func (s *SQLStore) UpdateSite(site models.Site) error { var existingToken string s.db.QueryRow(s.q("SELECT token FROM sites WHERE id=?"), site.ID).Scan(&existingToken) if site.Type == "push" && existingToken == "" { existingToken = generateToken() } - s.db.Exec(s.q("UPDATE sites SET name=?, url=?, type=?, token=?, interval=?, alert_id=?, check_ssl=?, threshold=?, max_retries=?, hostname=?, port=?, timeout=?, method=?, description=?, parent_id=?, accepted_codes=?, dns_resolve_type=?, dns_server=?, ignore_tls=?, paused=? WHERE id=?"), + _, err := s.db.Exec(s.q("UPDATE sites SET name=?, url=?, type=?, token=?, interval=?, alert_id=?, check_ssl=?, threshold=?, max_retries=?, hostname=?, port=?, timeout=?, method=?, description=?, parent_id=?, accepted_codes=?, dns_resolve_type=?, dns_server=?, ignore_tls=?, paused=? WHERE id=?"), site.Name, site.URL, site.Type, existingToken, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries, site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.Paused, site.ID) + return err } -func (s *SQLStore) UpdateSitePaused(id int, paused bool) { - s.db.Exec(s.q("UPDATE sites SET paused=? WHERE id=?"), paused, id) +func (s *SQLStore) UpdateSitePaused(id int, paused bool) error { + _, err := s.db.Exec(s.q("UPDATE sites SET paused=? WHERE id=?"), paused, id) + return err } -func (s *SQLStore) DeleteSite(id int) { - s.db.Exec(s.q("DELETE FROM sites WHERE id=?"), id) +func (s *SQLStore) DeleteSite(id int) error { + _, err := s.db.Exec(s.q("DELETE FROM sites WHERE id=?"), id) + if err != nil { + return err + } s.dialect.ResetSequenceOnEmpty(s.db, "sites") + return nil } -func (s *SQLStore) GetAllAlerts() []models.AlertConfig { +func (s *SQLStore) GetAllAlerts() ([]models.AlertConfig, error) { rows, err := s.db.Query("SELECT id, name, type, settings FROM alerts") if err != nil { - return []models.AlertConfig{} + return nil, err } defer rows.Close() var alerts []models.AlertConfig for rows.Next() { var a models.AlertConfig var settingsJSON string - rows.Scan(&a.ID, &a.Name, &a.Type, &settingsJSON) + if err := rows.Scan(&a.ID, &a.Name, &a.Type, &settingsJSON); err != nil { + return alerts, err + } json.Unmarshal([]byte(settingsJSON), &a.Settings) alerts = append(alerts, a) } - return alerts + return alerts, rows.Err() } -func (s *SQLStore) GetAlert(id int) (models.AlertConfig, bool) { +func (s *SQLStore) GetAlert(id int) (models.AlertConfig, error) { var a models.AlertConfig var settingsJSON string err := s.db.QueryRow(s.q("SELECT id, name, type, settings FROM alerts WHERE id = ?"), id).Scan(&a.ID, &a.Name, &a.Type, &settingsJSON) if err != nil { - return a, false + return a, err } json.Unmarshal([]byte(settingsJSON), &a.Settings) - return a, true + return a, nil } -func (s *SQLStore) AddAlert(name, aType string, settings map[string]string) { - jsonBytes, _ := json.Marshal(settings) - s.db.Exec(s.q("INSERT INTO alerts (name, type, settings) VALUES (?, ?, ?)"), name, aType, string(jsonBytes)) +func (s *SQLStore) AddAlert(name, aType string, settings map[string]string) error { + jsonBytes, err := json.Marshal(settings) + if err != nil { + return err + } + _, err = s.db.Exec(s.q("INSERT INTO alerts (name, type, settings) VALUES (?, ?, ?)"), name, aType, string(jsonBytes)) + return err } -func (s *SQLStore) UpdateAlert(id int, name, aType string, settings map[string]string) { - jsonBytes, _ := json.Marshal(settings) - s.db.Exec(s.q("UPDATE alerts SET name=?, type=?, settings=? WHERE id=?"), name, aType, string(jsonBytes), id) +func (s *SQLStore) UpdateAlert(id int, name, aType string, settings map[string]string) error { + jsonBytes, err := json.Marshal(settings) + if err != nil { + return err + } + _, err = s.db.Exec(s.q("UPDATE alerts SET name=?, type=?, settings=? WHERE id=?"), name, aType, string(jsonBytes), id) + return err } -func (s *SQLStore) DeleteAlert(id int) { - s.db.Exec(s.q("DELETE FROM alerts WHERE id=?"), id) +func (s *SQLStore) DeleteAlert(id int) error { + _, err := s.db.Exec(s.q("DELETE FROM alerts WHERE id=?"), id) + if err != nil { + return err + } s.dialect.ResetSequenceOnEmpty(s.db, "alerts") + return nil } -func (s *SQLStore) GetAllUsers() []models.User { +func (s *SQLStore) GetAllUsers() ([]models.User, error) { rows, err := s.db.Query("SELECT id, username, public_key, role FROM users") if err != nil { - return []models.User{} + return nil, err } defer rows.Close() var users []models.User for rows.Next() { var u models.User - rows.Scan(&u.ID, &u.Username, &u.PublicKey, &u.Role) + if err := rows.Scan(&u.ID, &u.Username, &u.PublicKey, &u.Role); err != nil { + return users, err + } users = append(users, u) } - return users + return users, rows.Err() } func (s *SQLStore) AddUser(username, publicKey, role string) error { @@ -174,14 +199,18 @@ func (s *SQLStore) DeleteUser(id int) error { return err } -func (s *SQLStore) SaveCheck(siteID int, latencyNs int64, isUp bool) { - s.db.Exec(s.q("INSERT INTO check_history (site_id, latency_ns, is_up) VALUES (?, ?, ?)"), siteID, latencyNs, isUp) - s.db.Exec(s.q(`DELETE FROM check_history WHERE site_id = ? AND id NOT IN ( +func (s *SQLStore) SaveCheck(siteID int, latencyNs int64, isUp bool) error { + _, err := s.db.Exec(s.q("INSERT INTO check_history (site_id, latency_ns, is_up) VALUES (?, ?, ?)"), siteID, latencyNs, isUp) + if err != nil { + return err + } + _, err = s.db.Exec(s.q(`DELETE FROM check_history WHERE site_id = ? AND id NOT IN ( SELECT id FROM check_history WHERE site_id = ? ORDER BY checked_at DESC LIMIT 1000 )`), siteID, siteID) + return err } -func (s *SQLStore) LoadAllHistory(limit int) map[int][]models.CheckRecord { +func (s *SQLStore) LoadAllHistory(limit int) (map[int][]models.CheckRecord, error) { result := make(map[int][]models.CheckRecord) rows, err := s.db.Query(s.q(` SELECT site_id, latency_ns, is_up FROM ( @@ -190,12 +219,14 @@ func (s *SQLStore) LoadAllHistory(limit int) map[int][]models.CheckRecord { FROM check_history ) sub WHERE rn <= ?`), limit) if err != nil { - return result + return result, err } defer rows.Close() for rows.Next() { var r models.CheckRecord - rows.Scan(&r.SiteID, &r.LatencyNs, &r.IsUp) + if err := rows.Scan(&r.SiteID, &r.LatencyNs, &r.IsUp); err != nil { + return result, err + } result[r.SiteID] = append(result[r.SiteID], r) } for id, records := range result { @@ -204,15 +235,23 @@ func (s *SQLStore) LoadAllHistory(limit int) map[int][]models.CheckRecord { } result[id] = records } - return result + return result, rows.Err() } -func (s *SQLStore) ExportData() models.Backup { - return models.Backup{ - Sites: s.GetSites(), - Alerts: s.GetAllAlerts(), - Users: s.GetAllUsers(), +func (s *SQLStore) ExportData() (models.Backup, error) { + sites, err := s.GetSites() + if err != nil { + return models.Backup{}, err } + alerts, err := s.GetAllAlerts() + if err != nil { + return models.Backup{}, err + } + users, err := s.GetAllUsers() + if err != nil { + return models.Backup{}, err + } + return models.Backup{Sites: sites, Alerts: alerts, Users: users}, nil } func (s *SQLStore) ImportData(data models.Backup) error { @@ -225,16 +264,25 @@ func (s *SQLStore) ImportData(data models.Backup) error { s.dialect.ImportWipe(tx) for _, u := range data.Users { - tx.Exec(s.q("INSERT INTO users (username, public_key, role) VALUES (?, ?, ?)"), u.Username, u.PublicKey, u.Role) + if _, err := tx.Exec(s.q("INSERT INTO users (username, public_key, role) VALUES (?, ?, ?)"), u.Username, u.PublicKey, u.Role); err != nil { + return err + } } for _, a := range data.Alerts { - jsonBytes, _ := json.Marshal(a.Settings) - tx.Exec(s.q("INSERT INTO alerts (id, name, type, settings) VALUES (?, ?, ?, ?)"), a.ID, a.Name, a.Type, string(jsonBytes)) + jsonBytes, err := json.Marshal(a.Settings) + if err != nil { + return err + } + if _, err := tx.Exec(s.q("INSERT INTO alerts (id, name, type, settings) VALUES (?, ?, ?, ?)"), a.ID, a.Name, a.Type, string(jsonBytes)); err != nil { + return err + } } for _, st := range data.Sites { - tx.Exec(s.q("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), + if _, err := tx.Exec(s.q("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls, paused) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), st.ID, st.Name, st.URL, st.Type, st.Token, st.Interval, st.AlertID, st.CheckSSL, st.ExpiryThreshold, st.MaxRetries, - st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS, st.Paused) + st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS, st.Paused); err != nil { + return err + } } s.dialect.ImportResetSequences(tx) diff --git a/internal/store/store.go b/internal/store/store.go index af3cd71..d119597 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -8,31 +8,31 @@ type Store interface { Init() error // Sites - GetSites() []models.Site - AddSite(site models.Site) - UpdateSite(site models.Site) - UpdateSitePaused(id int, paused bool) - DeleteSite(id int) + GetSites() ([]models.Site, error) + AddSite(site models.Site) error + UpdateSite(site models.Site) error + UpdateSitePaused(id int, paused bool) error + DeleteSite(id int) error // Alerts - GetAllAlerts() []models.AlertConfig - GetAlert(id int) (models.AlertConfig, bool) - AddAlert(name, aType string, settings map[string]string) - UpdateAlert(id int, name, aType string, settings map[string]string) - DeleteAlert(id int) + GetAllAlerts() ([]models.AlertConfig, error) + GetAlert(id int) (models.AlertConfig, error) + AddAlert(name, aType string, settings map[string]string) error + UpdateAlert(id int, name, aType string, settings map[string]string) error + DeleteAlert(id int) error // Users - GetAllUsers() []models.User + GetAllUsers() ([]models.User, error) AddUser(username, publicKey, role string) error UpdateUser(id int, username, publicKey, role string) error DeleteUser(id int) error // History - SaveCheck(siteID int, latencyNs int64, isUp bool) - LoadAllHistory(limit int) map[int][]models.CheckRecord + SaveCheck(siteID int, latencyNs int64, isUp bool) error + LoadAllHistory(limit int) (map[int][]models.CheckRecord, error) // Backup & Restore - ExportData() models.Backup + ExportData() (models.Backup, error) ImportData(data models.Backup) error } diff --git a/internal/tui/tab_alerts.go b/internal/tui/tab_alerts.go index 8a0447b..72bd19d 100644 --- a/internal/tui/tab_alerts.go +++ b/internal/tui/tab_alerts.go @@ -2,6 +2,7 @@ package tui import ( "fmt" + "go-upkeep/internal/monitor" "go-upkeep/internal/store" tea "github.com/charmbracelet/bubbletea" @@ -277,9 +278,13 @@ func (m *Model) submitAlertForm() { } if m.editID > 0 { - store.Get().UpdateAlert(m.editID, d.Name, d.AlertType, settings) + if err := store.Get().UpdateAlert(m.editID, d.Name, d.AlertType, settings); err != nil { + monitor.AddLog("Update alert failed: " + err.Error()) + } } else { - store.Get().AddAlert(d.Name, d.AlertType, settings) + if err := store.Get().AddAlert(d.Name, d.AlertType, settings); err != nil { + monitor.AddLog("Add alert failed: " + err.Error()) + } } m.state = stateDashboard } diff --git a/internal/tui/tab_sites.go b/internal/tui/tab_sites.go index 2656613..f1a2aa0 100644 --- a/internal/tui/tab_sites.go +++ b/internal/tui/tab_sites.go @@ -361,12 +361,14 @@ func (m *Model) initSiteHuhForm() tea.Cmd { } alertOpts := []huh.Option[string]{huh.NewOption("None", "0")} - if store.Get() != nil { - for _, a := range store.Get().GetAllAlerts() { - alertOpts = append(alertOpts, huh.NewOption( - fmt.Sprintf("%s (%s)", a.Name, a.Type), - strconv.Itoa(a.ID), - )) + if s := store.Get(); s != nil { + if alerts, err := s.GetAllAlerts(); err == nil { + for _, a := range alerts { + alertOpts = append(alertOpts, huh.NewOption( + fmt.Sprintf("%s (%s)", a.Name, a.Type), + strconv.Itoa(a.ID), + )) + } } } @@ -558,10 +560,14 @@ func (m *Model) submitSiteForm() { } if m.editID > 0 { - store.Get().UpdateSite(site) + if err := store.Get().UpdateSite(site); err != nil { + monitor.AddLog("Update site failed: " + err.Error()) + } monitor.UpdateSiteConfig(site) } else { - store.Get().AddSite(site) + if err := store.Get().AddSite(site); err != nil { + monitor.AddLog("Add site failed: " + err.Error()) + } } m.state = stateDashboard } diff --git a/internal/tui/tab_users.go b/internal/tui/tab_users.go index 4858b7c..77d4182 100644 --- a/internal/tui/tab_users.go +++ b/internal/tui/tab_users.go @@ -2,6 +2,7 @@ package tui import ( "fmt" + "go-upkeep/internal/monitor" "go-upkeep/internal/store" tea "github.com/charmbracelet/bubbletea" @@ -145,9 +146,13 @@ func (m *Model) initUserHuhForm() tea.Cmd { func (m *Model) submitUserForm() { d := m.userFormData if m.editID > 0 { - store.Get().UpdateUser(m.editID, d.Username, d.PublicKey, d.Role) + if err := store.Get().UpdateUser(m.editID, d.Username, d.PublicKey, d.Role); err != nil { + monitor.AddLog("Update user failed: " + err.Error()) + } } else { - store.Get().AddUser(d.Username, d.PublicKey, d.Role) + if err := store.Get().AddUser(d.Username, d.PublicKey, d.Role); err != nil { + monitor.AddLog("Add user failed: " + err.Error()) + } } m.state = stateUsers } diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 4972a3a..533c993 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -107,17 +107,23 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if keyMsg, ok := msg.(tea.KeyMsg); ok { switch keyMsg.String() { case "y", "Y": - if store.Get() != nil { + if s := store.Get(); s != nil { switch m.deleteTab { case 0: - store.Get().DeleteSite(m.deleteID) + if err := s.DeleteSite(m.deleteID); err != nil { + monitor.AddLog("Delete site failed: " + err.Error()) + } monitor.RemoveSite(m.deleteID) m.adjustCursor(len(m.sites) - 1) case 1: - store.Get().DeleteAlert(m.deleteID) + if err := s.DeleteAlert(m.deleteID); err != nil { + monitor.AddLog("Delete alert failed: " + err.Error()) + } m.adjustCursor(len(m.alerts) - 1) case 3: - store.Get().DeleteUser(m.deleteID) + if err := s.DeleteUser(m.deleteID); err != nil { + monitor.AddLog("Delete user failed: " + err.Error()) + } m.adjustCursor(len(m.users) - 1) } } @@ -313,8 +319,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { site := m.sites[m.cursor] monitor.ToggleSitePause(site.ID) site.Paused = !site.Paused - if store.Get() != nil { - store.Get().UpdateSitePaused(site.ID, site.Paused) + if s := store.Get(); s != nil { + _ = s.UpdateSitePaused(site.ID, site.Paused) } m.refreshData() } @@ -464,10 +470,14 @@ func (m *Model) refreshData() { } ordered = append(ordered, ungrouped...) m.sites = ordered - if store.Get() != nil { - m.alerts = store.Get().GetAllAlerts() + if s := store.Get(); s != nil { + if alerts, err := s.GetAllAlerts(); err == nil { + m.alerts = alerts + } if m.isAdmin { - m.users = store.Get().GetAllUsers() + if users, err := s.GetAllUsers(); err == nil { + m.users = users + } } } m.logViewport.SetContent(strings.Join(monitor.GetLogs(), "\n"))