feat(api): add DELETE /api/profile with Garmin client/tokenstore teardown

This commit is contained in:
2026-07-26 10:19:00 +02:00
parent e8c340a00e
commit ab8cdea214
4 changed files with 166 additions and 0 deletions

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"sync"
@@ -116,6 +117,36 @@ func (s *Server) syncFor(ctx context.Context, userID int64) (*appsync.Service, e
return svc, nil
}
// removeGarminClient drops userID's cached garmin.Client/sync.Service (if
// any) and every other per-user in-memory entry for userID, terminating the
// client's subprocess and best-effort removing its on-disk token-store
// directory. Called when a user's account has just been deleted from the
// DB, so nothing in memory keeps referencing a userID that no longer
// exists.
func (s *Server) removeGarminClient(userID int64) {
s.mu.Lock()
client, ok := s.userGarmin[userID]
delete(s.userGarmin, userID)
delete(s.userSync, userID)
delete(s.userAuthStatus, userID)
delete(s.userAuthMessage, userID)
delete(s.userSyncRunning, userID)
s.mu.Unlock()
if ok {
if err := client.Close(); err != nil {
log.Printf("api: close garmin client for deleted user %d: %v", userID, err)
}
}
if s.GarminBase.TokenStorePath == "" {
return
}
tokenStoreDir := filepath.Join(s.GarminBase.TokenStorePath, strconv.FormatInt(userID, 10))
if err := os.RemoveAll(tokenStoreDir); err != nil {
log.Printf("api: remove token store dir for deleted user %d: %v", userID, err)
}
}
// RunIncrementalSyncForAllUsers is called on a timer (see main.go) to sync
// every provisioned user in turn, replacing the old single-global-Service
// background loop.
@@ -167,6 +198,7 @@ func (s *Server) Router() http.Handler {
r.Route("/profile", func(r chi.Router) {
r.Get("/", s.handleGetProfile)
r.Put("/", s.handleUpdateProfile)
r.Delete("/", s.handleDeleteProfile)
})
r.Route("/auth", func(r chi.Router) {