lots of stuff, don't truly remember
This commit is contained in:
210
internal/goal/handler.go
Normal file
210
internal/goal/handler.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package goal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"rideaware/internal/config"
|
||||
"rideaware/internal/middleware"
|
||||
)
|
||||
|
||||
type Handler struct{}
|
||||
|
||||
func NewHandler() *Handler {
|
||||
return &Handler{}
|
||||
}
|
||||
|
||||
// CreateGoal POST /api/protected/goals
|
||||
func (h *Handler) CreateGoal(w http.ResponseWriter, r *http.Request) {
|
||||
claims := r.Context().Value(middleware.UserContextKey).(*config.CustomClaims)
|
||||
|
||||
var req struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
GoalType string `json:"goal_type"`
|
||||
TargetValue float64 `json:"target_value"`
|
||||
TargetDate *time.Time `json:"target_date"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Title == "" {
|
||||
writeError(w, http.StatusBadRequest, "title is required")
|
||||
return
|
||||
}
|
||||
|
||||
if req.TargetValue <= 0 {
|
||||
writeError(w, http.StatusBadRequest, "target_value must be greater than 0")
|
||||
return
|
||||
}
|
||||
|
||||
// Validate goal type
|
||||
gType := GoalType(req.GoalType)
|
||||
switch gType {
|
||||
case GoalDistance, GoalFrequency, GoalPower, GoalWeight, GoalCustom, "":
|
||||
if gType == "" {
|
||||
gType = GoalCustom
|
||||
}
|
||||
default:
|
||||
writeError(w, http.StatusBadRequest, "invalid goal_type")
|
||||
return
|
||||
}
|
||||
|
||||
goal := &Goal{
|
||||
UserID: claims.UserID,
|
||||
Title: req.Title,
|
||||
Description: req.Description,
|
||||
GoalType: gType,
|
||||
TargetValue: req.TargetValue,
|
||||
TargetDate: req.TargetDate,
|
||||
Status: StatusActive,
|
||||
}
|
||||
|
||||
repo := NewRepository()
|
||||
if err := repo.Create(goal); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to create goal")
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusCreated, goal)
|
||||
}
|
||||
|
||||
// GetGoals GET /api/protected/goals?status=active
|
||||
func (h *Handler) GetGoals(w http.ResponseWriter, r *http.Request) {
|
||||
claims := r.Context().Value(middleware.UserContextKey).(*config.CustomClaims)
|
||||
|
||||
statusFilter := r.URL.Query().Get("status")
|
||||
repo := NewRepository()
|
||||
|
||||
var goals []Goal
|
||||
var err error
|
||||
|
||||
if statusFilter != "" {
|
||||
goals, err = repo.ListByStatus(claims.UserID, GoalStatus(statusFilter))
|
||||
} else {
|
||||
goals, err = repo.List(claims.UserID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to fetch goals")
|
||||
return
|
||||
}
|
||||
|
||||
if goals == nil {
|
||||
goals = []Goal{}
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, goals)
|
||||
}
|
||||
|
||||
// UpdateGoal PUT /api/protected/goals?id=X
|
||||
func (h *Handler) UpdateGoal(w http.ResponseWriter, r *http.Request) {
|
||||
claims := r.Context().Value(middleware.UserContextKey).(*config.CustomClaims)
|
||||
|
||||
idStr := r.URL.Query().Get("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid goal id")
|
||||
return
|
||||
}
|
||||
|
||||
repo := NewRepository()
|
||||
goal, err := repo.GetByID(uint(id), claims.UserID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusNotFound, "goal not found")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
GoalType string `json:"goal_type"`
|
||||
TargetValue *float64 `json:"target_value"`
|
||||
CurrentValue *float64 `json:"current_value"`
|
||||
TargetDate *time.Time `json:"target_date"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Title != "" {
|
||||
goal.Title = req.Title
|
||||
}
|
||||
if req.Description != "" {
|
||||
goal.Description = req.Description
|
||||
}
|
||||
if req.GoalType != "" {
|
||||
gType := GoalType(req.GoalType)
|
||||
switch gType {
|
||||
case GoalDistance, GoalFrequency, GoalPower, GoalWeight, GoalCustom:
|
||||
goal.GoalType = gType
|
||||
default:
|
||||
writeError(w, http.StatusBadRequest, "invalid goal_type")
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.TargetValue != nil {
|
||||
goal.TargetValue = *req.TargetValue
|
||||
}
|
||||
if req.CurrentValue != nil {
|
||||
goal.CurrentValue = *req.CurrentValue
|
||||
}
|
||||
if req.TargetDate != nil {
|
||||
goal.TargetDate = req.TargetDate
|
||||
}
|
||||
if req.Status != "" {
|
||||
switch GoalStatus(req.Status) {
|
||||
case StatusActive, StatusCompleted, StatusArchived:
|
||||
goal.Status = GoalStatus(req.Status)
|
||||
default:
|
||||
writeError(w, http.StatusBadRequest, "invalid status")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := repo.Update(goal); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to update goal")
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, goal)
|
||||
}
|
||||
|
||||
// DeleteGoal DELETE /api/protected/goals?id=X
|
||||
func (h *Handler) DeleteGoal(w http.ResponseWriter, r *http.Request) {
|
||||
claims := r.Context().Value(middleware.UserContextKey).(*config.CustomClaims)
|
||||
|
||||
idStr := r.URL.Query().Get("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid goal id")
|
||||
return
|
||||
}
|
||||
|
||||
repo := NewRepository()
|
||||
if err := repo.Delete(uint(id), claims.UserID); err != nil {
|
||||
writeError(w, http.StatusNotFound, "goal not found")
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
json.NewEncoder(w).Encode(data)
|
||||
}
|
||||
|
||||
func writeError(w http.ResponseWriter, status int, message string) {
|
||||
writeJSON(w, status, map[string]string{"error": message})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user