Files
geniusrun/backend/internal/api/reclassify.go
Christophe Vila 0610897541 Replace per-kind reclassify with a single global reclassify that respects manual and Race locks
Manual assignments are the user's definitive word and Race assignments come
from a hard Garmin fact (eventType.typeKey), not a retunable rule -- neither
is ever touched by reclassify again, and Race can no longer be set by hand
via the review queue. Adds an Activities page so this locked/unlocked status
is visible per workout, since Review Queue only ever showed unresolved items.
2026-07-19 11:11:50 +02:00

52 lines
1.6 KiB
Go

package api
import (
"net/http"
"smartrun/backend/internal/store"
)
// handleReclassifyAll re-runs the rule engine for every activity except
// those that are locked:
// - a manual assignment is the user's definitive word and is never
// overwritten by the rule engine again;
// - an activity already assigned to Race is locked too, since that
// classification comes from a hard Garmin fact (eventType.typeKey ==
// "race"), not a rule the user might retune -- there's nothing to
// re-derive.
//
// It's a synchronous, bounded operation (unlike sync), so it runs inline
// rather than in the background.
func (s *Server) handleReclassifyAll(w http.ResponseWriter, r *http.Request) {
raceKind, hasRaceKind, err := s.DB.GetWorkoutKindByName(r.Context(), "Race")
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
assignments, err := s.DB.AllCurrentAssignments(r.Context())
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
var activityIDs []int64
for _, a := range assignments {
if a.AssignmentSource == store.AssignmentSourceManual {
continue
}
if hasRaceKind && a.WorkoutKindID != nil && *a.WorkoutKindID == raceKind.ID {
continue
}
activityIDs = append(activityIDs, a.ActivityID)
}
for _, activityID := range activityIDs {
if err := s.Sync.ClassifyActivity(r.Context(), activityID); err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
}
writeJSON(w, http.StatusOK, map[string]int{"reclassified": len(activityIDs)})
}