api: scope profile, workout-kind, Garmin auth, and progression handlers to userID
Pulled from userIDFromContext (never a URL/body parameter) and threaded into every store call plus the per-user garmin.Client accessor.
This commit is contained in:
@@ -25,24 +25,31 @@ func authStatusString(s garmin.AuthStatus) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) recordAuthResult(res garmin.AuthResult) {
|
func (s *Server) recordAuthResult(userID int64, res garmin.AuthResult) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
s.authStatus = res.Status
|
s.userAuthStatus[userID] = res.Status
|
||||||
s.authMessage = res.Message
|
s.userAuthMessage[userID] = res.Message
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAuthLogin(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleAuthLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
res, err := s.Garmin.Authenticate(r.Context())
|
userID := userIDFromContext(r.Context())
|
||||||
|
client, err := s.garminFor(r.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := client.Authenticate(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusBadGateway, err.Error())
|
writeError(w, http.StatusBadGateway, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.recordAuthResult(res)
|
s.recordAuthResult(userID, res)
|
||||||
writeJSON(w, http.StatusOK, authResponse{Status: authStatusString(res.Status), Message: res.Message})
|
writeJSON(w, http.StatusOK, authResponse{Status: authStatusString(res.Status), Message: res.Message})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAuthMFA(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleAuthMFA(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := userIDFromContext(r.Context())
|
||||||
var body struct {
|
var body struct {
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
}
|
}
|
||||||
@@ -55,18 +62,24 @@ func (s *Server) handleAuthMFA(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := s.Garmin.CompleteMFA(r.Context(), body.Code)
|
client, err := s.garminFor(r.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := client.CompleteMFA(r.Context(), body.Code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusBadGateway, err.Error())
|
writeError(w, http.StatusBadGateway, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.recordAuthResult(res)
|
s.recordAuthResult(userID, res)
|
||||||
writeJSON(w, http.StatusOK, authResponse{Status: authStatusString(res.Status), Message: res.Message})
|
writeJSON(w, http.StatusOK, authResponse{Status: authStatusString(res.Status), Message: res.Message})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAuthStatus(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleAuthStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := userIDFromContext(r.Context())
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
status, msg := s.authStatus, s.authMessage
|
status, msg := s.userAuthStatus[userID], s.userAuthMessage[userID]
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
writeJSON(w, http.StatusOK, authResponse{Status: authStatusString(status), Message: msg})
|
writeJSON(w, http.StatusOK, authResponse{Status: authStatusString(status), Message: msg})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ type workoutKindResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) toWorkoutKindResponse(r *http.Request, k store.WorkoutKind) (workoutKindResponse, error) {
|
func (s *Server) toWorkoutKindResponse(r *http.Request, k store.WorkoutKind) (workoutKindResponse, error) {
|
||||||
pace, err := s.DB.GetWorkoutTypePace(r.Context(), k.ID)
|
userID := userIDFromContext(r.Context())
|
||||||
|
pace, err := s.DB.GetWorkoutTypePace(r.Context(), userID, k.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return workoutKindResponse{}, err
|
return workoutKindResponse{}, err
|
||||||
}
|
}
|
||||||
@@ -71,8 +72,9 @@ func (req workoutKindRequest) validate() (classify.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleListWorkoutKinds(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleListWorkoutKinds(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := userIDFromContext(r.Context())
|
||||||
activeOnly := r.URL.Query().Get("include_inactive") != "true"
|
activeOnly := r.URL.Query().Get("include_inactive") != "true"
|
||||||
kinds, err := s.DB.ListWorkoutKinds(r.Context(), activeOnly)
|
kinds, err := s.DB.ListWorkoutKinds(r.Context(), userID, activeOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
@@ -90,12 +92,13 @@ func (s *Server) handleListWorkoutKinds(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleGetWorkoutKind(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleGetWorkoutKind(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := userIDFromContext(r.Context())
|
||||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusBadRequest, "invalid workout kind id")
|
writeError(w, http.StatusBadRequest, "invalid workout kind id")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
kind, ok, err := s.DB.GetWorkoutKind(r.Context(), id)
|
kind, ok, err := s.DB.GetWorkoutKind(r.Context(), userID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
@@ -113,12 +116,13 @@ func (s *Server) handleGetWorkoutKind(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleUpdateWorkoutKind(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleUpdateWorkoutKind(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := userIDFromContext(r.Context())
|
||||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusBadRequest, "invalid workout kind id")
|
writeError(w, http.StatusBadRequest, "invalid workout kind id")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
existing, ok, err := s.DB.GetWorkoutKind(r.Context(), id)
|
existing, ok, err := s.DB.GetWorkoutKind(r.Context(), userID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
@@ -143,14 +147,14 @@ func (s *Server) handleUpdateWorkoutKind(w http.ResponseWriter, r *http.Request)
|
|||||||
isActive = *req.IsActive
|
isActive = *req.IsActive
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.DB.UpdateWorkoutKind(r.Context(), store.WorkoutKind{
|
if err := s.DB.UpdateWorkoutKind(r.Context(), userID, store.WorkoutKind{
|
||||||
ID: id, Name: req.Name, Description: req.Description, Color: req.Color,
|
ID: id, Name: req.Name, Description: req.Description, Color: req.Color,
|
||||||
RuleJSON: string(req.Rule), Priority: req.Priority, IsActive: isActive,
|
RuleJSON: string(req.Rule), Priority: req.Priority, IsActive: isActive,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := s.DB.UpdateWorkoutTypePace(r.Context(), store.WorkoutTypePace{
|
if err := s.DB.UpdateWorkoutTypePace(r.Context(), userID, store.WorkoutTypePace{
|
||||||
WorkoutKindID: id,
|
WorkoutKindID: id,
|
||||||
PaceMinSecPerKm: req.PaceMinSecPerKm,
|
PaceMinSecPerKm: req.PaceMinSecPerKm,
|
||||||
PaceMaxSecPerKm: req.PaceMaxSecPerKm,
|
PaceMaxSecPerKm: req.PaceMaxSecPerKm,
|
||||||
@@ -161,7 +165,7 @@ func (s *Server) handleUpdateWorkoutKind(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
kind, _, _ := s.DB.GetWorkoutKind(r.Context(), id)
|
kind, _, _ := s.DB.GetWorkoutKind(r.Context(), userID, id)
|
||||||
resp, err := s.toWorkoutKindResponse(r, kind)
|
resp, err := s.toWorkoutKindResponse(r, kind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ func validateProfile(p store.Profile) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleGetProfile(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleGetProfile(w http.ResponseWriter, r *http.Request) {
|
||||||
p, err := s.DB.GetProfile(r.Context())
|
userID := userIDFromContext(r.Context())
|
||||||
|
p, err := s.DB.GetProfile(r.Context(), userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
@@ -45,6 +46,7 @@ func (s *Server) handleGetProfile(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleUpdateProfile(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleUpdateProfile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := userIDFromContext(r.Context())
|
||||||
var p store.Profile
|
var p store.Profile
|
||||||
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
|
||||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||||
@@ -55,13 +57,18 @@ func (s *Server) handleUpdateProfile(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.DB.UpdateProfile(r.Context(), p); err != nil {
|
if err := s.DB.UpdateProfile(r.Context(), userID, p); err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.Garmin.UpdateCredentials(p.GarminEmail, p.GarminPassword)
|
client, err := s.garminFor(r.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client.UpdateCredentials(p.GarminEmail, p.GarminPassword)
|
||||||
|
|
||||||
updated, err := s.DB.GetProfile(r.Context())
|
updated, err := s.DB.GetProfile(r.Context(), userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ func metricValue(metric string, a store.Activity) (float64, bool) {
|
|||||||
// handleProgression returns a time series of the requested metric for every
|
// handleProgression returns a time series of the requested metric for every
|
||||||
// activity currently assigned to a workout kind, for progression charts.
|
// activity currently assigned to a workout kind, for progression charts.
|
||||||
func (s *Server) handleProgression(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleProgression(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := userIDFromContext(r.Context())
|
||||||
kindID, err := strconv.ParseInt(chi.URLParam(r, "kindID"), 10, 64)
|
kindID, err := strconv.ParseInt(chi.URLParam(r, "kindID"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusBadRequest, "invalid workout kind id")
|
writeError(w, http.StatusBadRequest, "invalid workout kind id")
|
||||||
@@ -72,7 +73,7 @@ func (s *Server) handleProgression(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
|
from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
|
||||||
|
|
||||||
assignments, err := s.DB.AssignmentsForKind(r.Context(), kindID)
|
assignments, err := s.DB.AssignmentsForKind(r.Context(), userID, kindID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
@@ -80,7 +81,7 @@ func (s *Server) handleProgression(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
points := []progressionPoint{}
|
points := []progressionPoint{}
|
||||||
for _, a := range assignments {
|
for _, a := range assignments {
|
||||||
activity, ok, err := s.DB.GetActivity(r.Context(), a.ActivityID)
|
activity, ok, err := s.DB.GetActivity(r.Context(), userID, a.ActivityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(w, http.StatusInternalServerError, err.Error())
|
writeError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user