136 lines
3.4 KiB
Go
136 lines
3.4 KiB
Go
package api
|
|
|
|
import (
|
|
"database/sql"
|
|
"net/http"
|
|
|
|
"training-tracker/internal/models"
|
|
)
|
|
|
|
type ExerciseHandler struct {
|
|
repo ExerciseRepository
|
|
}
|
|
|
|
func NewExerciseHandler(repo ExerciseRepository) *ExerciseHandler {
|
|
return &ExerciseHandler{repo: repo}
|
|
}
|
|
|
|
func (h *ExerciseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
id, _ := parseID(r, "/api/exercises/")
|
|
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
if id > 0 {
|
|
h.getByID(w, r, id)
|
|
} else {
|
|
h.list(w, r)
|
|
}
|
|
case http.MethodPost:
|
|
h.create(w, r)
|
|
case http.MethodPut:
|
|
if id > 0 {
|
|
h.update(w, r, id)
|
|
} else {
|
|
respondError(w, http.StatusBadRequest, "exercise ID required")
|
|
}
|
|
case http.MethodDelete:
|
|
if id > 0 {
|
|
h.delete(w, r, id)
|
|
} else {
|
|
respondError(w, http.StatusBadRequest, "exercise ID required")
|
|
}
|
|
default:
|
|
respondError(w, http.StatusMethodNotAllowed, "method not allowed")
|
|
}
|
|
}
|
|
|
|
func (h *ExerciseHandler) list(w http.ResponseWriter, r *http.Request) {
|
|
exercises, err := h.repo.List(r.Context())
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "failed to list exercises")
|
|
return
|
|
}
|
|
if exercises == nil {
|
|
exercises = []models.Exercise{}
|
|
}
|
|
respondJSON(w, http.StatusOK, exercises)
|
|
}
|
|
|
|
func (h *ExerciseHandler) getByID(w http.ResponseWriter, r *http.Request, id int64) {
|
|
exercise, err := h.repo.GetByID(r.Context(), id)
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "failed to get exercise")
|
|
return
|
|
}
|
|
if exercise == nil {
|
|
respondError(w, http.StatusNotFound, "exercise not found")
|
|
return
|
|
}
|
|
respondJSON(w, http.StatusOK, exercise)
|
|
}
|
|
|
|
func (h *ExerciseHandler) create(w http.ResponseWriter, r *http.Request) {
|
|
var req models.CreateExerciseRequest
|
|
if err := decodeJSON(r, &req); err != nil {
|
|
respondError(w, http.StatusBadRequest, "invalid request body")
|
|
return
|
|
}
|
|
|
|
if req.Name == "" {
|
|
respondError(w, http.StatusBadRequest, "name is required")
|
|
return
|
|
}
|
|
if req.Type != models.ExerciseTypeStrength && req.Type != models.ExerciseTypeCardio {
|
|
respondError(w, http.StatusBadRequest, "type must be 'strength' or 'cardio'")
|
|
return
|
|
}
|
|
|
|
exercise, err := h.repo.Create(r.Context(), &req)
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "failed to create exercise")
|
|
return
|
|
}
|
|
respondJSON(w, http.StatusCreated, exercise)
|
|
}
|
|
|
|
func (h *ExerciseHandler) update(w http.ResponseWriter, r *http.Request, id int64) {
|
|
var req models.CreateExerciseRequest
|
|
if err := decodeJSON(r, &req); err != nil {
|
|
respondError(w, http.StatusBadRequest, "invalid request body")
|
|
return
|
|
}
|
|
|
|
if req.Name == "" {
|
|
respondError(w, http.StatusBadRequest, "name is required")
|
|
return
|
|
}
|
|
if req.Type != models.ExerciseTypeStrength && req.Type != models.ExerciseTypeCardio {
|
|
respondError(w, http.StatusBadRequest, "type must be 'strength' or 'cardio'")
|
|
return
|
|
}
|
|
|
|
exercise, err := h.repo.Update(r.Context(), id, &req)
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "failed to update exercise")
|
|
return
|
|
}
|
|
if exercise == nil {
|
|
respondError(w, http.StatusNotFound, "exercise not found")
|
|
return
|
|
}
|
|
respondJSON(w, http.StatusOK, exercise)
|
|
}
|
|
|
|
func (h *ExerciseHandler) delete(w http.ResponseWriter, r *http.Request, id int64) {
|
|
err := h.repo.Delete(r.Context(), id)
|
|
if err == sql.ErrNoRows {
|
|
respondError(w, http.StatusNotFound, "exercise not found")
|
|
return
|
|
}
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "failed to delete exercise")
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|